文章列表

Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等

作者:微信小助手

<blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="50" data-source-title=""> <section class="js_blockquote_digest"> <section> <p><span style="color: rgb(136, 136, 136);font-size: 15px;">作者:搜云库技术团队<br></span></p> <section> <section> <p><span style="color: rgb(136, 136, 136);">来源地址:</span><span style="color: rgb(136, 136, 136);">segmentfault.com/a/1190000017766364</span></p> </section> </section> </section> </section> </blockquote> <p style="margin-top: 1.5em;margin-bottom: 1.5em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, &quot;Source Han Sans SC&quot;, &quot;Noto Sans CJK SC&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: 15px;">在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类。介绍的内容如下:</span></p> <p><span style="font-size: 15px;">1.公平锁 / 非公平锁</span></p> <p><span style="font-size: 15px;">2.可重入锁 / 不可重入锁</span></p> <p><span style="font-size: 15px;">3.独享锁 / 共享锁</span></p> <p><span style="font-size: 15px;">4.互斥锁 / 读写锁</span></p> <p><span style="font-size: 15px;">5.乐观锁 / 悲观锁</span></p> <p><span style="font-size: 15px;">6.分段锁</span></p> <p><span style="font-size: 15px;">7.偏向锁 / 轻量级锁 / 重量级锁</span></p> <p><span style="font-size: 15px;">8.自旋锁</span></p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, &quot;Source Han Sans SC&quot;, &quot;Noto Sans CJK SC&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: 15px;">上面是很多锁的名词,这些分类并不是全是指锁的状态,有的指锁的特性,有的指锁的设计,下面总结的内容是对每个锁的名词进行一定的解释。</span></p> <h2><span style="font-size: 15px;"><strong>公平锁 / 非公平锁</strong></span></h2> <p style="margin-top: 1.5em;margin-bottom: 1.5em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, &quot;Source Han Sans SC&quot;, &quot;Noto Sans CJK SC&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: 15px;"><strong>公平锁</strong></span></p> <p><span style="font-size: 15px;">公平锁是指多个线程按照申请锁的顺序来获取锁。</span></p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, &quot;Source Han Sans SC&quot;, &quot;Noto Sans CJK SC&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: 15px;"><strong>非公平锁</strong></span></p> <p><span style="font-size: 15px;">非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。</span></p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, &quot;Source Han Sans SC&quot;, &quot;Noto Sans CJK SC&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: 15px;">对于</span><code style="font-family: &quot;Source Code Pro&quot;, Consolas, Menlo, Monaco, &quot;Courier New&quot;, monospace;font-size: 0.93em;padding: 2px 4px;color: rgb(199, 37, 78);background-color: rgb(249, 242, 244);border-radius: 4px;"><span style="font-size: 15px;">Java ReentrantLock</span></code><span style="font-size: 15px;">而言,通过构造函数指定该锁是否是公平锁,默认是非公平锁。非公平锁的优点在于吞吐量比公平锁大。<br>对于</span><code style="font-family: &quot;Source Code Pro&quot;, Consolas, Menlo, Monaco, &quot;Courier New&quot;, monospace;font-size: 0.93em;padding: 2px 4px;color: rgb(199, 37, 78);background-color: rgb(249, 242, 244);border-radius: 4px;"><span style="font-size: 15px;">Synchronized</span></code><span style="font-size: 15px;">而言,也是一种非公平锁。由于其并不像</span><code style="font-family: &quot;Source Code Pro&quot;, Consolas, Menlo, Monaco, &quot;Courier New&quot;, monospace;font-size: 0.93em;padding: 2px 4px;color: rgb(199, 37, 78);background-color: rgb(249, 242, 244);border-radius: 4px;"><span style="font-size: 15px;">ReentrantLock</span></code><span style="font-size: 15px;">是通过</span><code style="font-family: &quot;Source Code Pro&quot;, Consolas, Menlo, Monaco, &quot;Courier New&quot;, monospace;font-size: 0.93em;padding: 2px 4px;color: rgb(199, 37, 78);background-color: rgb(249, 242, 244);border-radius: 4px;"><span style="font-size: 15px;">AQS</span></code><span style="font-size: 15px;">的来实现线程调度,所以并没有任何办法使其变成公平锁。</span></p> <h2><span style="font-size: 15px;"><strong>可重入锁 / 不可重入锁</strong></span></h2> <p style="margin-top: 1.5em;margin-bottom: 1.5em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, &quot;Source Han Sans SC&quot;, &quot;Noto Sans CJK SC&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: 15px;"><strong>可重入锁</strong></span></p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, &quot;Source Han Sans SC&quot;, &quot;Noto Sans CJK SC&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: 15px;">广义上的可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者class),这样的锁就叫做可重入锁。</span><code style="font-family: &quot;Source Code Pro&quot;, Consolas, Menlo, Monaco, &quot;Courier New&quot;, monospace;font-size: 0.93em;padding: 2px 4px;color: rgb(199, 37, 78);background-color: rgb(249, 242, 244);border-radius: 4px;"><span style="font-size: 15px;">ReentrantLock</span></code><span style="font-size: 15px;">和</span><code style="font-family: &quot;Source Code Pro&quot;, Consolas, Menlo, Monaco, &quot;Courier New&quot;, monospace;font-size: 0.93em;padding: 2px 4px;color: rgb(199, 37, 78);background-color: rgb(249, 242, 244);border-radius: 4px;"><span style="font-size: 15px;">synchronized</span></code><span style="font-size: 15px;">都是可重入锁</span></p> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" class="mpa-template" mpa-preserve="t"> <pre style="margin:0;padding:0;border-radius:none;background:none;"><code style="border-radius: 4px;font-size: 0.85em;margin: 0px 0.15em;background: rgb(40, 44, 52);color: rgb(171, 178, 191);display: block;padding: 6px;overflow-x: auto;white-space: nowrap;" class="hljs-default"><span class="hljs-default-function" style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 270px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"><span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 79px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">synchronized</span> <span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">void</span> <span class="hljs-default-title" style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(97, 174, 238);font-weight: 400;font-style: normal;">setA</span><span class="hljs-default-params" style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 13px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;">()</span> <span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">throws</span> Exception</span>{<br> &nbsp; &nbsp;Thread.sleep(<span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">1000</span>);<br> &nbsp; &nbsp;setB();<br>}<br><span class="hljs-default-function" style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 270px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"><span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 79px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">synchronized</span> <span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">void</span> <span class="hljs-default-title" style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(97, 174, 238);font-weight: 400;font-style: normal;">setB</span><span class="hljs-default-params" style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 13px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;">()</span> <span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">throws</span> Exception</span>{<br> &nbsp; &nbsp;Thread.sleep(<span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">1000</span>);<br>}</code></pre> </section> <p style="margin-top: 1.5em;margin-bottom: 1.5em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, &quot;Source Han Sans SC&quot;, &quot;Noto Sans CJK SC&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: 15px;">上面的代码就是一个可重入锁的一个特点,如果不是可重入锁的话,setB可能不会被当前线程执行,可能造成死锁。</span></p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, &quot;Source Han Sans SC&quot;, &quot;Noto Sans CJK SC&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: 15px;"><strong>不可重入锁</strong></span></p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, &quot;Source Han Sans SC&quot;, &quot;Noto Sans CJK SC&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: 15px;">不可重入锁,与可重入锁相反,不可递归调用,递归调用就发生死锁。看到一个经典的讲解,使用自旋锁来模拟一个不可重入锁,代码如下</span></p> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" class="mpa-template" mpa-preserve="t"> <pre style="margin:0;padding:0;border-radius:none;background:none;"><code style="border-radius: 4px;font-size: 0.85em;margin: 0px 0.15em;background: rgb(40, 44, 52);color: rgb(171, 178, 191);display: block;padding: 6px;overflow-x: auto;white-space: nowrap;" class="hljs-default"><span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">import</span> java.util.concurrent.atomic.AtomicReference;<br><br><span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">public</span> <span class="hljs-default-class" style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 145px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"><span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">class</span> <span class="hljs-default-title" style="color: rgb(230, 192, 123);background: rgba(0, 0, 0, 0);display: inline;width: 99px;text-decoration: none solid rgb(230, 192, 123);font-weight: 400;font-style: normal;">UnreentrantLock</span> </span>{<br><br> &nbsp; &nbsp;<span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 46px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">private</span> AtomicReference&lt;Thread&gt; owner = <span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">new</span> AtomicReference&lt;Thread&gt;();<br><br> &nbsp; &nbsp;<span class="hljs-default-function" style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 126px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"><span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">public</span> <span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 27px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">void</span> <span class="hljs-default-title" style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 27px;text-decoration: none solid rgb(97, 174, 238);font-weight: 400;font-style: normal;">lock</span><span class="hljs-default-params" style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 13px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;">()</span> </span>{<br> &nbsp; &nbsp; &nbsp; &nbsp;Thread current = Thread.currentThread();<br> &nbsp; &nbsp; &nbsp; &nbsp;<span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 292px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;">//这句是很经典的“自旋”语法,AtomicInteger中也有</span><br> &nbsp; &nbsp; &nbsp; &nbsp;<span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 19px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">for</span> (;;) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 13px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">if</span> (!owner.compareAndSet(<span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">null</span>, current)) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">return</span>;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp;}<br><br> &nbsp; &nbsp;<span class="hljs-default-function" style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 139px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"><span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">public</span> <span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 27px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">void</span> <span class="hljs-default-title" style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(97, 174, 238);font-weight: 400;font-style: normal;">unlock</span><span class="hljs-default-params" style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 13px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;">()</span> </span>{<br> &nbsp; &nbsp; &nbsp; &nbsp;Thread current = Thread.currentThread();<br> &nbsp; &nbsp; &nbsp; &nbsp;owner.compareAndSet(current, <span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">null</span>);<br> &nbsp; &nbsp;}<br>}</code></pre> </section> <p style="margin-top: 1.5em;margin-bottom: 1.5em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, &quot;Source Han Sans SC&quot;, &quot;Noto Sans CJK SC&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: 15px;">代码也比较简单,使用原子引用来存放线程,同一线程两次调用lock()方法,如果不执行unlock()释放锁的话,第二次调用自旋的时候就会产生死锁,这个锁就不是可重入的,而实际上同一个线程不必每次都去释放锁再来获取锁,这样的调度切换是很耗资源的。</span></p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, &quot;Source Han Sans SC&quot;, &quot;Noto Sans CJK SC&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: 15px;"><strong>把它变成一个可重入锁</strong>:</span></p> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" class="mpa-template" mpa-preserve="t"> <pre style="margin:0;padding:0;border-radius:none;background:none;"><code style="border-radius: 4px;font-size: 0.85em;margin: 0px 0.15em;background: rgb(40, 44, 52);color: rgb(171, 178, 191);display: block;padding: 6px;overflow-x: auto;white-space: nowrap;" class="hljs-default">import java.util.concurrent.atomic.AtomicReference;<br><br><span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">public</span> <span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">class</span> <span class="hljs-default-title" style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 99px;text-decoration: none solid rgb(97, 174, 238);font-weight: 400;font-style: normal;">UnreentrantLock</span> {<br><br> &nbsp; &nbsp;<span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 46px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">private</span> AtomicReference&lt;Thread&gt; owner = <span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">new</span> AtomicReference&lt;Thread&gt;();<br> &nbsp; &nbsp;<span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 46px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">private</span> <span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">int</span> state = <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 7px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">0</span>;<br><br> &nbsp; &nbsp;<span class="hljs-default-function" style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 126px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"><span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">public</span> <span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 27px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">void</span> <span class="hljs-default-title" style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 27px;text-decoration: none solid rgb(97, 174, 238);font-weight: 400;font-style: normal;">lock</span>(<span class="hljs-default-params" style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 0px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"></span>) </span>{<br> &nbsp; &nbsp; &nbsp; &nbsp;Thread current = Thread.currentThread();<br> &nbsp; &nbsp; &nbsp; &nbsp;<span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 13px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">if</span> (current == owner.<span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">get</span>()) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;state++;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">return</span>;<br> &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp;<span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 304px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;">//这句是很经典的“自旋”式语法,AtomicInteger中也有</span><br> &nbsp; &nbsp; &nbsp; &nbsp;<span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 19px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">for</span> (;;) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 13px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">if</span> (!owner.compareAndSet(<span class="hljs-default-literal" style="color: rgb(86, 182, 194);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(86, 182, 194);font-weight: 400;font-style: normal;">null</span>, current)) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">return</span>;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp;}<br><br> &nbsp; &nbsp;<span class="hljs-default-function" style="color: rgb(171, 178, 191);background: rgba(0, 0, 0, 0);display: inline;width: 139px;text-decoration: none solid rgb(171, 178, 191);font-weight: 400;font-style: normal;"><span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">public</span> <span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 27px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">void</span> <span class="hljs-default-title" style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(97, 174, 238);font-weight: 400;font-style: normal;">unlock</span>(<span class="hljs-default-params" style="color: rgb(171, 17

Java设计模式(转)——7.装饰模式

作者:じ☆ve宝贝

7.装饰模式(Decorator) 顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例,关系图如下: ![装饰设计模式](/upload/content15.png "装饰设计模式") Source类是被装饰类,Decorator类是一个装饰类,可以为Source类动态的添加一些功能,代码如下: ``` public interface Sourceable { public void method(); } ``` ``` public class Source implements Sourceable { @Override public void method() { System.out.println("the original method!"); } } ``` ``` public class Decorator implements Sourceable { private Sourceable source; public Decorator(Sourceable source){ super(); this.source = source; } @Override public void method() { System.out.println("before decorator!"); source.method(); System.out.println("after decorator!"); } } ``` 测试类: ``` public class DecoratorTest { public static void main(String[] args) { Sourceable source = new Source(); Sourceable obj = new Decorator(source); obj.method(); } } ``` 输出: before decorator! the original method! after decorator! 装饰器模式的应用场景: 1、需要扩展一个类的功能。 2、动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点,继承的功能是静态的,不能动态增删。) 缺点:产生过多相似的对象,不易排错!

StartSSL下载crt证书后转成tomcat需要的jks证书

作者:じ☆ve宝贝

### 1.首先安装OpenSSL ### 2.从key和crt生成pkcs12格式的keystore ``` openssl pkcs12 -export -in 2_www.studyjava.cn.crt -inkey www.studyjava.cn.key -out mycert.p12 -name tomcat -CAfile myCA.crt ``` ### 3.生成tomcat需要的keystore ``` keytool -importkeystore -v -srckeystore mycert.p12 -srcstoretype pkcs12 -srcstorepass password -destkeystore tomcat.keystore -deststoretype jks -deststorepass password ``` ### 4.tomcat配置server.xml ``` <Connector port="443" protocol="org.apache.coyote.http11.Http11Protocol" maxThreads="150" SSLEnabled="true" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreFile="/tomcat/keys/20161024www.studyjava.cn.keystore" keystorePass="password" /> ```

恕我直言,IDEA 的 Debug 调试,你可能只用了 10%

作者:微信小助手

<p style="white-space: normal;text-align: center;" data-mpa-powered-by="yiban.io"><img class="rich_pages" data-ratio="0.6666666666666666" data-s="300,640" data-type="png" data-w="492" src="/upload/4cd539297545735ac33ef3e2a7b33705.png"></p> <p style="white-space: normal;text-align: center;"><span style="font-size: 15px;"><span style="font-family: 宋体;"></span><span style="color: black;font-family: 微软雅黑, sans-serif;letter-spacing: 2px;">扫描下方二维码&nbsp;</span><span style="font-family: -apple-system-font, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Hiragino Sans GB, Microsoft YaHei UI, Microsoft YaHei, Arial, sans-serif;letter-spacing: 0.544px;color: rgb(201, 56, 28);"><span style="font-family: 微软雅黑, sans-serif;letter-spacing: 2px;font-size: 20px;"><strong>试听</strong></span><span style="font-family: 微软雅黑, sans-serif;letter-spacing: 2px;">&nbsp;</span></span></span></p> <p style="white-space: normal;text-align: center;"><img class="rich_pages" data-ratio="0.6666666666666666" data-s="300,640" data-type="png" data-w="203" src="/upload/de78368b47ee77f05053f965e3949722.png"></p> <ul class=" list-paddingleft-2" style=""> <li><p style="line-height: 2em;"><span style="font-size: 14px;">一、Debug开篇</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 14px;">二、基本用法&amp;快捷键</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 14px;">三、变量查看</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 14px;">四、计算表达式</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 14px;">五、智能步入</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 14px;">六、断点条件设置</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 14px;">七、多线程调试</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 14px;">八、回退断点</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 14px;">九、中断Debug</span></p></li> </ul> <hr style="margin-top: 16px;margin-bottom: 16px;box-sizing: content-box;letter-spacing: 0.544px;white-space: normal;border-width: 0px;border-style: none;border-color: initial;height: 2px;background-color: rgb(231, 231, 231);color: rgb(52, 73, 94);font-family: Source Sans Pro, Helvetica Neue, Arial, sans-serif;font-size: 16px;text-align: start;"> <p style="margin-top: 0.8em; margin-bottom: 0.8em; letter-spacing: 0.544px; white-space: normal; color: rgb(52, 73, 94); font-family: &quot;Source Sans Pro&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif; font-size: 16px; text-align: start; background-color: rgb(255, 255, 255); line-height: 2em;">Debug用来追踪代码的运行流程,通常在程序运行过程中出现异常,启用Debug模式可以分析定位异常发生的位置,以及在运行过程中参数的变化。通常我们也可以启用Debug模式来跟踪代码的运行流程去学习三方框架的源码。</p> <p style="margin-top: 0.8em; margin-bottom: 0.8em; letter-spacing: 0.544px; white-space: normal; color: rgb(52, 73, 94); font-family: &quot;Source Sans Pro&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif; font-size: 16px; text-align: start; background-color: rgb(255, 255, 255); line-height: 2em;">所以学习下如何在Intellij IDEA中使用好Debug。</p> <h1 style="margin-top: 35px; margin-bottom: 15px; padding-bottom: 0.5em; font-weight: bold; font-size: 1.2rem; letter-spacing: 0.544px; white-space: normal; cursor: text; border-bottom: 1px solid rgb(221, 221, 221); color: rgb(52, 73, 94); font-family: &quot;Source Sans Pro&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif; text-align: start; background-color: rgb(255, 255, 255); line-height: 2em;">一、Debug开篇</h1> <p style="margin-top: 0.8em; margin-bottom: 0.8em; letter-spacing: 0.544px; white-space: normal; color: rgb(52, 73, 94); font-family: &quot;Source Sans Pro&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif; font-size: 16px; text-align: start; background-color: rgb(255, 255, 255); line-height: 2em;">首先看下IDEA中Debug模式下的界面。</p> <p style="margin-top: 0.8em; margin-bottom: 0.8em; letter-spacing: 0.544px; white-space: normal; color: rgb(52, 73, 94); font-family: &quot;Source Sans Pro&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif; font-size: 16px; text-align: start; background-color: rgb(255, 255, 255); line-height: 2em;">�

从一次线上故障思考 Java 问题定位思路

作者:微信小助手

<p style="max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(255, 0, 0);font-size: 14px;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(255, 41, 65);line-height: 22.4px;">(点击</span><span style="max-width: 100%;line-height: 22.4px;color: rgb(0, 128, 255);">上方公众号</span><span style="max-width: 100%;color: rgb(255, 41, 65);line-height: 22.4px;">,可快速关注)</span></span></p> <p style="max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;letter-spacing: 0.544px;text-align: justify;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <blockquote style="max-width: 100%;color: rgb(51, 51, 51);font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;letter-spacing: 0.544px;text-align: justify;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;text-align: left;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;word-wrap: break-word !important;">来源:melonstreet ,</span></p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;text-align: left;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;word-wrap: break-word !important;">www.cnblogs.com/QG-whz/p/9647614.html</span></p> </blockquote> <p><br></p> <p><strong><span style="color: rgb(255, 76, 65);">问题出现:现网CPU飙高,Full GC告警</span></strong></p> <p><br></p> <p>CGI 服务发布到现网后,现网机器出现了Full GC告警,同时CPU飙高99%。在优先恢复现网服务正常后,开始着手定位Full GC的问题。在现场只能够抓到四个GC线程占用了很高的CPU,无法抓到引发Full GC的线程。查看了服务故障期间的错误日志,发现更多的是由于Full GC引起的问题服务异常日志,无法确定Full GC的根源。为了查找问题的根源,只能从发布本身入手去查问题,发现一次bugfix的提交,有可能触发一个死循环逻辑:</p> <p><br></p> <blockquote> <p style="text-align: left;"><span style="font-size: 12px;color: rgb(136, 136, 136);">for(int i = 1 ;i <= totalPage ;i++) {</span></p> <p style="text-align: left;"><span style="font-size: 12px;color: rgb(136, 136, 136);">            String path = path_prefix + "?cmd=txt_preview&page=" + String.valueOf(i) + "&sign=" + fileSignature;</span></p> <p style="text-align: left;"><span style="font-size: 12px;color: rgb(136, 136, 136);">            url_list.add(path);</span></p> <p style="text-align: left;"><span style="font-size: 12px;color: rgb(136, 136, 136);">}</span></p> </blockquote> <p><br></p> <p>循环中的参数 totalPage 为 long 类型,由一个外部参数进行赋值。当外部参数非常大,超过 int 的最大值时,i递增到int的最大值后,i++ 会发生翻转,变成一个负数,从而使 for 会进入死循环。利用下面这段代码可以试验:</p> <p><br></p> <blockquote> <p style="text-align: left;"><span style="font-size: 12px;color: rgb(136, 136, 136);">public static void main(String[] args) {</span></p> <p style="text-align: left;"><span style="font-size: 12px;color: rgb(136, 136, 136);">    long totalPage = Long.MAX_VALUE;</span></p> <p style="text-align: left;"><span style="font-size: 12px;color: rgb(136, 136, 136);">    for(int i = 0 ;i<totalPage;i++){</span></p> <p style="text-align: left;"><span style="font-size: 12px;color: rgb(136, 136, 136);">        if(i<0){</span></p> <p style="text-align: left;"><span style="font-size: 12px;color: rgb(136, 136, 136);">            System.out.println(i);</span></p> <p style="text-align: left;"><span style="font-size: 12px;color: rgb(136, 136, 136);">        }</span></p> <p style="text-align: left;"><span style="font-size: 12px;color: rgb(136, 136, 136);">    }</span></p> <p style="text-align: left;"><span style="font-size: 12px;color: rgb(136, 136, 136);">}</span></p> </blockquote> <p><br></p> <p>通过日志,发现外部确实传递了一个非常大的参数:</p> <p><br></p> <p style="text-align: center;"><img class="aligncenter size-full wp-image-29892" data-ratio="0.055379746835443035" src="/upload/6a7c9f7c0875a3da7035e2bb20523be9.png" data-type="png" data-w="632" style="border-width: 0px;border-style: initial;border-color: initial;font-size: 0px;color: transparent;vertical-align: middle;text-align: center;margin: 0px;top: 0px;left: 0px;right: 0px;bottom: 0px;" title="610439-20180914171537456-2117831862"></p> <p><br></p> <p>确认了当命中逻辑的时候,会进入一个死循环。在循环中不断进行字符串的拼接与list的Add操作,很快就会耗尽JVM堆内存导致Full GC。经过测算,实际上并不需要死循环,只要是一个比较大的循环,就能够引发Full GC。对totlePage的大小做了限定后,发布了新版本,没有再出现Full GC的问题。</p> <p><br></p> <p><strong><span style="color: rgb(255, 76, 65);">现场还原:重现问题,探索定位思路</span></strong></p> <p><br></p> <p>回顾排查问题的过程并不高效,最开始怀疑过是否是打包有问题或使用的jdk版本不对,花了较多的时间确认打包问题。另一方面,发布带出的代码较多,通过重复review代码无法很快锁定问题。为了探索一种更有效的问题定位方法,我将有问题的代码重新部署到机器上,手动构造请求触发bug,探索定位此类问题的通用思路。</p> <p><br></p> <p><strong><span style="color: rgb(123, 12, 0);">如何确定bug可以导致CPU飙升?为何会引发OOM?</span></strong></p> <p><br></p> <p>1) 在 Java 服务上开启 JMX,在本地使用 VisualVm 来查看 Java 服务在运行过程中的内存、GC、线程等信息。VisualVM 是 Sun 的一个 OpenJDK 项目,它是集成了多个 JDK 命令工具的一个可视化工具,它主要用来监控 JVM 的运行情况,可以用它来查看和浏览 Heap Dump、Thread Dump、内存对象实例情况、GC 执行情况、CPU 消耗以及类的装载情况,也可以使用它来创建必要信息的日志。</p> <p><br></p> <p style="text-align: center;"><img class="aligncenter size-large wp-image-29893" data-ratio="0.5009765625" src="/upload/3fff4822d78d64b22c087e212a9a7f54.png" data-type="png" data-w="1024" style="border-width: 0px;border-style: initial;border-color: initial;font-size: 0px;color: transparent;vertical-align: middle;text-align: center;margin: 0px;top: 0px;left: 0px;right: 0px;bottom: 0px;" title="610439-20180914171601606-395373695"></p> <p><br></p> <p>可以看到逻辑被命中的时候,CPU确实是升到100%的,此时也发生了Full GC告警。尝试着多发了几次请求,服务直接就挂掉了。这里有个问题是:不是已经Full GC了吗,为什么还会发生OOM?实际上,虽然JVM已经开始回收内存,但是由于对象被引用,这些内存是回收不掉的。从GC日志可以看到回收的情况:</p> <p><br></p> <p style="text-align: center;"><img class="aligncenter size-large wp-image-29894" data-ratio="0.2265625" src="/upload/3130d63840a86f1a2dc15133c14feb61.png" data-type="png" data-w="1024" style="border-width: 0px;border-style: initial;border-color: initial;font-size: 0px;color: transparent;vertical-align: middle;text-align: center;margin: 0px;top: 0px;left: 0px;right: 0px;bottom: 0px;" title="610439-20180914171611464-1898061671"></p> <p><br></p> <p>从GC日志中可以看到,新生代的Eden区域与老年代都已经被占满。如果新生代放不下对象的时候,object会直接被放到老年代中。除了GC日志,也可以使用jstat命令来堆Java堆内存的使用情况进行统计展示:</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">jstat -gcutil 12309 1000 10</span></p> </blockquote> <p><br></p> <p>1000为统计的间隔,单位为毫秒,10为统计的次数,输出如下:</p> <p><br></p> <p style="text-align: center;"><img class="aligncenter size-full wp-image-29895" data-ratio="0.29506008010680906" src="/upload/e12a9e4707131d4cfd0cb1fa6a63cdef.png" data-type="png" data-w="749" style="border-width: 0px;border-style: initial;border-color: initial;font-size: 0px;color: transparent;vertical-align: middle;text-align: center;margin: 0px;top: 0px;left: 0px;right: 0px;bottom: 0px;" title="610439-20180914171644184-360950821"></p> <p><br></p> <p>从输出中同样可以看到E(Eden)区与O(Old)区都已经被占满了。其他几个输出项的含义如下:</p> <p><br></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p>YGC: 从启动到采样时Young Generation GC的次数</p></li> <li><p>YGCT: 从启动到采样时Young Generation GC所用的时间 (s).</p></li> <li><p>FGC: 从启动到采样时Old Generation GC的次数.</p></li> <li><p>FGCT: 从启动到采样时Old Generation GC所用的时间 (s).</p></li> <li><p>GCT: 从启动到采样时GC所用的总时间 (s).</p></li> </ul> <p><br></p> <p>可以看到JVM一直在尝试回收老年代,但是一直没能将内存回收回来。</p> <p><br></p> <p><strong><span style="color: rgb(123, 12, 0);">如何获取占用CPU最高的线程id?</span></strong></p> <p><br></p> <p>2)可以登上机器,确认下是什么线程使 CPU 飙高。先ps查看 Java 进程的 PID:</p> <p><br></p> <p style="text-align: center;"><img class="aligncenter size-full wp-image-29896" data-ratio="0.12177650429799428" src="/upload/2a7c0ea23dc980f1d9a5178cee4ae7e3.png" data-type="png" data-w="698" style="border-width: 0px;border-style: initial;border-color: initial;font-size: 0px;color: transparent;vertical-align: middle;text-align: center;margin: 0px;top: 0px;left: 0px;right: 0px;bottom: 0px;" title="610439-20180914171735005-189532605"></p> <p><br></p> <p>拿到进程 pid 后,可以使用 top 命令,来看是什么线程占用了 CPU。</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">top -p 12309 -H</span></p> </blockquote> <p><br></p> <p>-p 用于指定进程,-H 用于获取每个线程的信息,从 top 输出的内容,可以看到有四个线程占用了非常高的 CPU:</p> <p><br></p> <p style="text-align: center;"><img class="aligncenter size-full wp-image-29897" data-ratio="0.2781136638452237" src="/upload/c67156917e949bdd30be38b48b18783a.png" data-type="png" data-w="827" style="border-width: 0px;border-style: initial;border-color: initial;font-size: 0px;color: transparent;vertical-align: middle;text-align: center;margin: 0px;top: 0px;left: 0px;right: 0px;bottom: 0px;" title="610439-20180914171748829-1934986704"></p> <p><br></p> <p>到这里可以拿到12313、12312、12311、12314这四个线程id。为了确定这些是什么线程,需要使用 jstack 命令来查看这几个是什么线程。</p> <p><br></p> <p><strong><span style="color: rgb(123, 12, 0);">高占用CPU的是什么线程?</span></strong></p> <p><br></p> <p>3) jstack 是 Java 虚拟机自带的一种堆栈跟踪工具,用于打印出给定的 Java 进程 ID 或 core file 或远程调试服务的 Java 堆栈信息。使用下面命令,将 Java 进程的堆栈信息打印到文件中:</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">jstack -l 12309 > stack.log</span></p> </blockquote> <p><br></p> <p>在线程堆栈信息中,线程 id 是使用十六进制来表示的。将上面四个四个线程 id 转换为16进制,分别是0X3019、0X3018、0×3017、0x301A。在 stack.log 中可以找到这几个线程:</p> <p><br></p> <p style="text-align: center;"><img class="aligncenter size-full wp-image-29898" data-ratio="0.35301353013530135" src="/upload/bf0d797caba523975033ccd3cb08cc.png" data-type="png" data-w="813" style="border-width: 0px;border-style: initial;border-color: initial;font-size: 0px;color: transparent;vertical-align: middle;text-align: center;margin: 0px;top: 0px;left: 0px;right: 0px;bottom: 0px;" title="610439-20180914171757933-129540261"></p> <p><br></p> <p>到这里可以确定的是,死循环引发了Full GC,四个GC线程一直尝试着回收内存,这四个线程将CPU占满。</p> <p><br></p> <p><strong><span style="color: rgb(123, 12, 0);">是哪些对象占用了内存?</span></strong></p> <p><br></p> <p>4)Full GC、OOM、CPU 被占满的问题都得到了解答。那么再次遇到类似的线上问题时,如何确定或者缩小问题范围,找到导致问题的代码呢?这时候需要进一步观察的是 Java 堆内存的信息,查看是什么对象占用了内存。可以使用上文提到的 VisualVM 来生成 headdump 文件:</p> <p><br></p> <p style="text-align: center;"><img class="aligncenter size-large wp-image-29899" data-ratio="0.298828125" src="/upload/672b8b6fd17ea51ae951257fa24666ab.png" data-type="png" data-w="1024" style="border-width: 0px;border-style: initial;border-color: initial;font-size: 0px;color: transparent;vertical-align: middle;text-align: center;margin: 0px;top: 0px;left: 0px;right: 0px;bottom: 0px;" title="610439-20180914171805645-1217442888"></p> <p><br></p> <p>也可以在机器上使用 jmap 命令来生成 head dump 文件。</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">jmap -dump:live,format=b,file=headInfo.hprof 12309</span></p> </blockquote> <p><br></p> <p>live 这个参数表示我们需要抓取的是目前在生命周期内的内存对象,也就是说 GC 收不走的对象,在这种场景下,我们需要的就是这些内存的信息。生成了 hprof 文件后,可以拉回到本地,使用 VisualVM 来打开它进行分析。打开后可以看到:</p> <p><br></p> <p style="text-align: center;"><img class="aligncenter size-large wp-image-29900" data-ratio="0.6162109375" src="/upload/27a45fad9cddbdc5a1ef7ee26d40bdc.png" data-type="png" data-w="1024" style="border-width: 0px;border-style: initial;border-color: initial;font-size: 0px;color: transparent;vertical-align: middle;text-align: center;margin: 0px;top: 0px;left: 0px;right: 0px;bottom: 0px;" title="610439-20180914171814568-448726500"></p> <p><br></p> <p>从信息中可以看到,字符串 char[] 在占了内存的73%,因此可以确定的是内存泄漏与字符串有关。通常生成的 headdump 文件会很大,也可以使用下面的命令,来查看占用内存最多的类型:</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">jmap -histo 12309 > heap.log</span></p> </blockquote> <p><br></p> <p>输出内容如下:</p> <p><br></p> <p style="text-align: center;"><img class="aligncenter size-large wp-image-29901" data-ratio="0.400390625" src="/upload/143f65cf6d0999a61fe54c5e42f3ca06.png" data-type="png" data-w="1024" style="border-width: 0px;border-style: initial;border-color: initial;font-size: 0px;color: transparent;vertical-align: middle;text-align: center;margin: 0px;top: 0px;left: 0px;right: 0px;bottom: 0px;" title="610439-20180914171821963-179832827"></p> <p><br></p> <p><strong><span style="color: rgb(123, 12, 0);">能否对堆内对象进行查询?</span></strong></p> <p><br></p> <p>5) 到这里突然有个想法,如果能够分析出相似度高的字符串,那么有比较大的可能是这些字符串存在泄漏,从而可以缩小问题代码的范围。确实是有这么一种工具来对堆内的对象进行分析,也就是OQL(Object Query Language),在VisualVM中可以对headdump文件执行对象查询,下面是一个示例,查找包含内容最多的List:</p> <p><br></p> <blockquote> <p style="text-align: left;"><span style="font-size: 12px;color: rgb(136, 136, 136);">select map(top(heap.objects('java.util.ArrayList'), 'rhs.size - lhs.size', 5),"toHtml(it)+'='+it.size")</span></p> </blockquote> <p><br></p> <p>查询结果如下:</p> <p><br></p> <p style="text-align: center;"><img class="aligncenter size-large wp-image-29902" data-ratio="0.5693359375" src="/upload/2508bb73cbc48689d8d2343f828b6c78.png" data-type="png" data-w="1024" style="border-width: 0px;border-style: initial;border-color: initial;font-size: 0px;color: transparent;vertical-align: middle;text-align: center;margin: 0px;top: 0px;left: 0px;right: 0px;bottom: 0px;" title="610439-20180914172322073-828703972"></p> <p><br></p> <p>如何查找到相似度最高的字符串,还在继续学习研究中。</p> <p><br></p> <p><strong><span style="color: rgb(255, 76, 65);">一些疑问与总结</span></strong></p> <p><br></p> <p>1)为什么无法抓到引发 Full GC 的线程?一个猜测是线程抛出 OOM 异常之后就被终止了,线程只存活了很短的时间。</p> <p><br></p> <p>2)为什么对 Eden 区回收后存活的对象,不会被拷贝到 survivor 区?从上面的 GC 日志可以看到,BeforeGC 与 AfterGC,新生代中的两个survivor 区(也就是from\to)一直都是0%,这里猜想可能是 survivor 区太小,没有足够的空间存放从 Eden 区拷贝拷贝过来的对象。同时老年代也没有足够的空间(已经99%了),因此 JVM 的 GC 基本没有什么有效的回收操作。</p> <p><br></p> <p>3)重现问题时,在日志里发现了一个 OOM 的错误信息:</p> <p><br></p> <blockquote> <p style="text-align: left;"><span style="font-size: 12px;color: rgb(136, 136, 136);">java.lang.OutOfMemoryError: GC overhead limit exceeded</span></p> </blockquote> <p><br></p> <p>这种情况发生的原因是, 程序基本上耗尽了所有的可用内存, GC 也清理不了。JVM 执行垃圾收集的时间比例太大, 有效的运算量太小。默认情况下, 如果GC花费的时间超过 98%, 并且 GC 回收的内存少于 2%, JVM 就会抛出这个错误。从这里也可以看到 GC 线程一直在尝试回收内存,但是回收效果实在太差,也就是第二点提到的。</p> <p><br></p> <p>4)当时在线上环境出现问题时,看到很多 log4 j的错误日志信息,是什么原因?猜测大概是写日志的 I/O 操作要经过内存,而内存已经被使用光,无法进行写操作所导致。这些问题都可以进一步研究。</p> <p><br></p> <p>对于一般的 OOM 问题,通过这几个方面的思考,大致可以锁定问题所在,或是缩小问题可能发生的范围。例如对某些特定类型的内存泄漏来说,到这一步已经可以分析出是什么类型导致内存泄漏。而对本案例来说,根据排查结果可以优先考虑的是字符串的泄露,代码 review 中查看是否有操作字符串的地方,而不会将问题的优先级锁定在打包问题上。</p> <p><br></p> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box;color: rgb(51, 51, 51);font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;letter-spacing: 0.544px;text-align: justify;white-space: normal;background-color: rgb(255, 255, 255);word-wrap: break-word !important;"> <section class="" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;box-sizing: border-box;text-align: left;word-wrap: break-word !important;"> <section class="" style="padding: 10px;max-width: 100%;box-sizing: border-box;display: inline-block;width: 668px;border-width: 1px;border-style: solid;border-color: rgb(226, 226, 226);box-shadow: rgb(226, 226, 226) 0px 16px 1px -13px;word-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box;word-wrap: break-word !important;"> <section class="" style="max-width: 100%;box-sizing: border-box;word-wrap: break-word !important;"> <section class="" style="max-width: 100%;box-sizing: border-box;color: rgb(93, 93, 93);word-wrap: break-word !important;"> <p class="" style="max-width: 100%;box-sizing: border-box;min-height: 1em;font-size: 13px;word-wrap: break-word !important;">【关于投稿】</p> <p class="" style="max-width: 100%;box-sizing: border-box;min-height: 1em;font-size: 13px;word-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <p class="" style="max-width: 100%;box-sizing: border-box;min-height: 1em;font-size: 13px;word-wrap: break-word !important;">如果大家有原创好文投稿,请直接给公号发送留言。</p> <p class="" style="max-width: 100%;box-sizing: border-box;min-height: 1em;font-size: 13px;word-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <p class="" style="max-width: 100%;box-sizing: border-box;min-height: 1em;font-size: 13px;word-wrap: break-word !important;"><span style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;word-wrap: break-word !important;">① 留言格式:</span><br style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;word-wrap: break-word !important;">【投稿】+《 文章标题》+ 文章链接</span><br style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;word-wrap: break-word !important;"><br style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;word-wrap: break-word !important;">② 示例:</span><br style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;word-wrap: break-word !important;">【投稿】《不要自称是程序员,我十多年的 IT 职场总结》:http://blog.jobbole.com/94148/</span><br style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;word-wrap: break-word !important;"><br style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;word-wrap: break-word !important;">③ 最后请附上您的个人简介哈~</span></span></p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"></p> </section> </section> </section> </section> </section> </section> <p style="max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;letter-spacing: 0.544px;text-align: justify;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;color: rgb(255, 169, 0);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;">看完本文有收获?请转发分享给更多人</span></p> <p style="max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(255, 169, 0);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;">关注「ImportNew」,提升Java技能</strong></p> <p style="max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.9166666666666666" data-s="300,640" data-type="png" data-w="600" width="auto" src="/upload/899866149276fa5fddb73c61ae04be64.png" style="box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;visibility: visible !important;width: 600px !important;"></p>

一次非常有意思的SQL优化经历:从30248.271s到0.001s

作者:微信小助手

<p style="text-align: right;"><strong style="font-size: 14px; line-height: 26px; white-space: normal; widows: 1; text-align: center; font-family: Helvetica, Tahoma, Arial, sans-serif;"><img class="" data-ratio="0.6666666666666666" data-type="jpeg" src="/upload/b322e590475923595ae9297db3283533.jpg" style="visibility: visible !important; width:auto !important;max-width:100% !important;height:auto !important;" width="auto"></strong></p> <p data-mpa-powered-by="yiban.io" style="margin: 5px 16px; white-space: normal; letter-spacing: 0.544px; caret-color: rgb(51, 51, 51); word-spacing: 2px; text-align: center; line-height: normal;"><img class="" data-backh="371" data-backw="556" data-before-oversubscription-url="https://mmbiz.qpic.cn/mmbiz_jpg/SJm51egHPPG62U6xFs2NAy0rDus9uh793plicPS1oavedr2leJCoXVw0kdl1oNx1rnQ96JF8yo3CG5GwiawFlgYg/0?wx_fmt=jpeg" data-copyright="0" data-cropselx1="0" data-cropselx2="556" data-cropsely1="0" data-cropsely2="371" data-ratio="0.6666666666666666" data-s="300,640" data-type="jpeg" data-w="1280" src="/upload/6d9f80cd6532b687f384651b90fea19.jpg" style="letter-spacing: 0.544px; width: 531px; visibility: visible !important;"></p> <p style="white-space: normal; letter-spacing: 0.544px; widows: 1; text-align: center;"><span style="color: rgb(119, 119, 119); font-size: 13px; letter-spacing: 0.544px;"><span style="color: rgb(136, 136, 136); font-size: 14px; font-variant-numeric: normal; letter-spacing: 1px; line-height: normal;"></span></span></p> <p style="white-space: normal; color: rgb(154, 154, 154); font-size: 15px;"><span style="font-size: 14px;"></span></p> <blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="49" data-source-title="" style="white-space: normal;"> <section class="js_blockquote_digest"> <section> <p style="color: rgb(154, 154, 154); font-size: 15px;"><span style="font-size: 14px;"><strong>原文链接:</strong></span></p> <p style="color: rgb(154, 154, 154); font-size: 15px;"><span style="font-size: 14px;">https://www.toutiao.com/i6668275333034148356</span></p> </section> </section> </blockquote> <p style="white-space: normal; letter-spacing: 0.544px; widows: 1; text-align: center;"><span style="color: rgb(136, 136, 136); font-size: 14px; font-variant-numeric: normal; letter-spacing: 1px; line-height: normal;"></span><span style="color: rgb(136, 136, 136); font-size: 14px; font-variant-numeric: normal; letter-spacing: 1px; line-height: normal;"></span><br></p> <p></p> <section class="mpa-template" data-mpa-template-id="1562268" data-mpa-color="null" data-mpa-category="收藏" style="white-space: normal;"> <section> <section class="layout"> <section style="margin-top: 1em; margin-bottom: 1em; color: rgb(51, 51, 51); border-bottom: 2px solid rgb(236, 68, 68); clear: both;"> <section style="padding-top: 3px; padding-right: 10px; padding-left: 10px; display: inline-block; color: rgb(255, 255, 255); border-top-left-radius: 3px; border-top-right-radius: 3px; height: 28px; background-color: rgb(236, 68, 68);"> <span mpa-is-content="t">场景</span> </section> <section style="margin-left: 2px; border-top: 28px solid transparent; border-right-color: rgb(206, 206, 206); border-bottom: 0px solid transparent; border-left: 15px solid rgb(206, 206, 206); display: inline-block; vertical-align: top;"></section> </section> </section> </section> </section> <p></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">用的数据库是mysql5.6,下面简单的介绍下场景</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;"><strong>课程表:</strong></p> <p style="white-space: normal; text-align: center;"><img class="rich_pages" data-ratio="0.6666666666666666" data-s="300,640" data-type="png" data-w="272" src="/upload/75900740a5e05a5e21d67966192cec98.png"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">数据100条</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;"><strong>学生表:</strong></p> <p style="white-space: normal; text-align: center;"><img class="rich_pages" data-ratio="0.6666666666666666" data-s="300,640" data-type="png" data-w="280" src="/upload/a0d5f801722d0b154d6881fab439103d.png"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">数据70000条</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;"><strong>学生成绩表SC:</strong></p> <p style="white-space: normal; text-align: center;"><img class="rich_pages" data-ratio="0.6666666666666666" data-s="300,640" data-type="png" data-w="301" src="/upload/be6b2ef366445086b47aa463ebc31a9a.png"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">数据70w条</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">查询目的:</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;"><strong>查找语文考100分的考生</strong></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">查询语句:</p> <p style="white-space: normal; text-align: center;"><img class="rich_pages" data-ratio="0.6666666666666666" data-s="300,640" data-type="png" data-w="669" src="/upload/d4e44bf40674cefd14b51b725f44d8da.png"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">执行时间:<strong>30248.271s</strong></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">为什么这么慢?先来查看下查询计划:</p> <p style="white-space: normal; text-align: center;"><img class="rich_pages" data-ratio="0.6666666666666666" data-s="300,640" data-type="png" data-w="675" src="/upload/f58e09b208007680026fe19418ae719a.png"></p> <p style="white-space: normal;"><img class="" data-ratio="0.6666666666666666" data-type="jpeg" data-w="759" src="/upload/c0b11b90575ea4ebcdc3a002ac8cd3e2.jpg" style="margin: 10px auto; -webkit-tap-highlight-color: transparent; border-style: none; display: block; width:auto !important;max-width:100% !important;height:auto !important;"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">发现没有用到索引,type全是ALL,那么首先想到的就是建立一个索引,建立索引的字段当然是在where条件的字段。</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">先给sc表的c_id和score建个索引</p> <p style="white-space: normal; text-align: center;"><img class="rich_pages" data-ratio="0.6666666666666666" data-s="300,640" data-type="png" data-w="370" src="/upload/42b6bb50e790b4ce14da85a3ab09a537.png"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">再次执行上述查询语句,时间为:&nbsp;1.054s</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">快了3w多倍,大大缩短了查询时间,看来索引能极大程度的提高查询效率,看来建索引很有必要,很多时候都忘记建索引了,数据量小的的时候压根没感觉,这优化感觉挺爽。</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">但是1s的时间还是太长了,还能进行优化吗,仔细看执行计划:</p> <p style="white-space: normal;"><img class="" data-ratio="0.6666666666666666" data-type="jpeg" data-w="809" src="/upload/c0ef6f4a3f02d178da13d94b6d2cae1b.jpg" style="margin: 10px auto; -webkit-tap-highlight-color: transparent; border-style: none; display: block; width:auto !important;max-width:100% !important;height:auto !important;"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">查看优化后的sql:</p> <p style="white-space: normal; text-align: center;"><img class="rich_pages" data-ratio="0.6666666666666666" data-s="300,640" data-type="png" data-w="512" src="/upload/ccbc1428b80d9281c6f273d2e93cf8a4.png"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">补充:这里有网友问怎么查看优化后的语句</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">方法如下:</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">在命令窗口执行</p> <p style="white-space: normal;"><img class="" data-ratio="0.6666666666666666" data-type="jpeg" data-w="879" src="/upload/9a5752beb6d336e54422cc3cdaf7c128.jpg" style="margin: 10px auto; -webkit-tap-highlight-color: transparent; border-style: none; display: block; width:auto !important;max-width:100% !important;height:auto !important;"></p> <p style="white-space: normal;"><img class="" data-ratio="0.6666666666666666" data-type="jpeg" data-w="422" src="/upload/792dfe03d820c14171edbe6c014886b6.jpg" style="margin: 10px auto; -webkit-tap-highlight-color: transparent; border-style: none; display: block; width:auto !important;max-width:100% !important;height:auto !important;"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">有type=all</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">按照我之前的想法,该sql的执行的顺序应该是先执行子查询</p> <p style="white-space: normal; text-align: center;"><img class="rich_pages" data-ratio="0.6666666666666666" data-s="300,640" data-type="png" data-w="495" src="/upload/12af15176a507aa1ed32920bce432267.png"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">耗时:0.001s</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">得到如下结果:</p> <p style="white-space: normal;"><img class="" data-ratio="0.6666666666666666" data-type="jpeg" data-w="102" src="/upload/a4e6a971419b75da60ddd9a92e3aa08d.jpg" style="margin: 10px auto; -webkit-tap-highlight-color: transparent; border-style: none; display: block; width:auto !important;max-width:100% !important;height:auto !important;"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">然后再执行</p> <p style="white-space: normal; text-align: center;"><img class="rich_pages" data-ratio="0.6666666666666666" data-s="300,640" data-type="png" data-w="439" src="/upload/5bdf1c405285e1c35e5507fe04f496ef.png"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">耗时:0.001s</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">这样就是相当快了啊,Mysql竟然不是先执行里层的查询,而是将sql优化成了exists子句,并出现了EPENDENT SUBQUERY,</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">mysql是先执行外层查询,再执行里层的查询,这样就要循环70007*11=770077次。</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">那么改用连接查询呢?</p> <p style="white-space: normal; text-align: center;"><img class="rich_pages" data-ratio="0.6666666666666666" data-s="300,640" data-type="png" data-w="293" src="/upload/228559c10c7fc8f83a8dd93e35c68d5c.png"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">这里为了重新分析连接查询的情况,先暂时删除索引sc_c_id_index,sc_score_index</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">执行时间是:0.057s</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">效率有所提高,看看执行计划:</p> <p style="white-space: normal;"><img class="" data-ratio="0.6666666666666666" data-type="jpeg" data-w="743" src="/upload/d1cbd5c365f36c0b76b35ec5ee2732fe.jpg" style="margin: 10px auto; -webkit-tap-highlight-color: transparent; border-style: none; display: block; width:auto !important;max-width:100% !important;height:auto !important;"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">这里有连表的情况出现,我猜想是不是要给sc表的s_id建立个索引</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">CREATE index sc_s_id_index on SC(s_id);</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">show index from SC</p> <p style="white-space: normal;"><img class="" data-ratio="0.6666666666666666" data-type="jpeg" data-w="271" src="/upload/623f28ed1d79757cc697a4524d927551.jpg" style="margin: 10px auto; -webkit-tap-highlight-color: transparent; border-style: none; display: block; width:auto !important;max-width:100% !important;height:auto !important;"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">在执行连接查询</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">时间:&nbsp;1.076s,竟然时间还变长了,什么原因?查看执行计划:</p> <p style="white-space: normal;"><img class="" data-ratio="0.6666666666666666" data-type="jpeg" data-w="760" src="/upload/e061621fac3d1bd476c7cf043786b08b.jpg" style="margin: 10px auto; -webkit-tap-highlight-color: transparent; border-style: none; display: block; width:auto !important;max-width:100% !important;height:auto !important;"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">优化后的查询语句为:</p> <p style="white-space: normal; text-align: center;"><img class="rich_pages" data-ratio="0.6666666666666666" data-s="300,640" data-type="png" data-w="393" src="/upload/2eb321721ff9038c79027eee55dd1386.png"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">貌似是先做的连接查询,再执行的where过滤</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">回到前面的执行计划:</p> <p style="white-space: normal;"><img class="" data-ratio="0.6666666666666666" data-type="jpeg" data-w="743" src="/upload/d1cbd5c365f36c0b76b35ec5ee2732fe.jpg" style="margin: 10px auto; -webkit-tap-highlight-color: transparent; border-style: none; display: block; width:auto !important;max-width:100% !important;height:auto !important;"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">这里是先做的where过滤,再做连表,执行计划还不是固定的,那么我们先看下标准的sql执行顺序:</p> <p style="white-space: normal;"><img class="" data-ratio="0.6666666666666666" data-type="jpeg" data-w="345" src="/upload/ddc11a9d1008721a505606c426177915.jpg" style="margin: 10px auto; -webkit-tap-highlight-color: transparent; border-style: none; display: block; width:auto !important;max-width:100% !important;height:auto !important;"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">正常情况下是先join再where过滤,但是我们这里的情况,如果先join,将会有70w条数据发送join做操,因此先执行where</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">过滤是明智方案,现在为了排除mysql的查询优化,我自己写一条优化后的sql</p> <p style="white-space: normal; text-align: center;"><img class="rich_pages" data-ratio="0.6666666666666666" data-s="300,640" data-type="png" data-w="354" src="/upload/43544149c400f6046466c4828bdee917.png"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">即先执行sc表的过滤,再进行表连接,执行时间为:0.054s</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">和之前没有建s_id索引的时间差不多</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">查看执行计划:</p> <p style="white-space: normal;"><img class="" data-ratio="0.6666666666666666" data-type="jpeg" data-w="793" src="/upload/fb007133d9beef7a412003cc0d409963.jpg" style="margin: 10px auto; -webkit-tap-highlight-color: transparent; border-style: none; display: block; width:auto !important;max-width:100% !important;height:auto !important;"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">先提取sc再连表,这样效率就高多了,现在的问题是提取sc的时候出现了扫描表,那么现在可以明确需要建立相关索引</p> <p style="white-space: normal; text-align: center;"><img class="rich_pages" data-ratio="0.6666666666666666" data-s="300,640" data-type="png" data-w="356" src="/upload/caee6cbcd5839a21ba9f730d2a9e93a2.png"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">再执行查询:</p> <p style="white-space: normal; text-align: center;"><img class="rich_pages" data-ratio="0.6666666666666666" data-s="300,640" data-type="png" data-w="351" src="/upload/83806f0a13c011211c18468d75c0d71c.png"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">执行时间为:0.001s,这个时间相当靠谱,快了50倍</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">执行计划:</p> <p style="white-space: normal;"><img class="" data-ratio="0.6666666666666666" data-type="jpeg" data-w="807" src="/upload/da85718fa5dc1c445093e2991a4bf4d3.jpg" style="margin: 10px auto; -webkit-tap-highlight-color: transparent; border-style: none; display: block; width:auto !important;max-width:100% !important;height:auto !important;"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">我们会看到,先提取sc,再连表,都用到了索引。</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">那么再来执行下sql</p> <p style="white-space: normal; text-align: center;"><img class="rich_pages" data-ratio="0.6666666666666666" data-s="300,640" data-type="png" data-w="290" src="/upload/f384fa9bba3be91f7a5aa22a09251200.png"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">执行时间0.001s</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">执行计划:</p> <p style="white-space: normal;"><img class="" data-ratio="0.6666666666666666" data-type="jpeg" data-w="896" src="/upload/4e90830538683060ac70b47457e9ed1d.jpg" style="margin: 10px auto; -webkit-tap-highlight-color: transparent; border-style: none; display: block; width:auto !important;max-width:100% !important;height:auto !important;"></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">这里是mysql进行了查询语句优化,先执行了where过滤,再执行连接操作,且都用到了索引。</p> <p></p> <section class="mpa-template" data-mpa-template-id="1562268" data-mpa-color="null" data-mpa-category="收藏" style="white-space: normal;"> <section> <section class="layout"> <section style="margin-top: 1em; margin-bottom: 1em; color: rgb(51, 51, 51); border-bottom: 2px solid rgb(236, 68, 68); clear: both;"> <section style="padding-top: 3px; padding-right: 10px; padding-left: 10px; display: inline-block; color: rgb(255, 255, 255); border-top-left-radius: 3px; border-top-right-radius: 3px; height: 28px; background-color: rgb(236, 68, 68);"> <span mpa-is-content="t">总结</span> </section> <section style="margin-left: 2px; border-top: 28px solid transparent; border-right-color: rgb(206, 206, 206); border-bottom: 0px solid transparent; border-left: 15px solid rgb(206, 206, 206); display: inline-block; vertical-align: top;"></section> </section> </section> </section> </section> <p></p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">1、mysql嵌套子查询效率确实比较低</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">2、可以将其优化成连接查询</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">3、建立合适的索引</p> <p style="margin-top: 15px; margin-bottom: 15px; white-space: normal; line-height: 2em;">4、学会分析sql执行计划,mysql会对sql进行优化,所以分析执行计划很重要</p> <p style="color: rgb(51, 51, 51); font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; font-size: 17px; letter-spacing: 0.544px; white-space: normal; widows: 1; line-height: 25.6px; text-align: center;"><span style="color: rgb(120, 172, 254);"><strong><strong style="font-family: 微软雅黑; line-height: normal;"><span style="line-height: 25.6px;">推荐程序员必备微信号&nbsp;</span></strong></strong></span><br></p> <p style="color: rgb(51, 51, 51); font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; font-size: 17px; letter-spacing: 0.544px; white-space: normal; widows: 1; line-height: 25.6px; text-align: center;"><span style="color: rgb(120, 172, 254);"><strong><span style="font-family: 微软雅黑; line-height: normal;">▼</span></strong></span></p> <blockquote style="margin: 0.2em; padding-top: 10px; padding-right: 10px; padding-bottom: 10px; border-top: 3px solid rgb(201, 201, 201); border-right: 3px solid rgb(201, 201, 201); border-bottom: 3px solid rgb(201, 201, 201); border-left-color: rgb(201, 201, 201); border-image: initial; color: rgba(0, 0, 0, 0.498); font-size: 13px; letter-spacing: 0.544px; white-space: normal; widows: 1; line-height: 25.6px; font-family: 微软雅黑; box-shadow: rgb(170, 170, 170) 0px 0px 10px; text-align: center;"> <section style="color: inherit; line-height: 25.6px; display: inline-block;"> <section class="" style="margin-top: 0.2em; padding-right: 0.5em; padding-bottom: 5px; padding-left: 0.5em; color: rgb(107, 77, 64); font-size: 1.8em; line-height: 1; border-bottom: 1px solid rgb(107, 77, 64); border-top-color: rgb(107, 77, 64); border-right-color: rgb(107, 77, 64); border-left-color: rgb(107, 77, 64);"> <p><br></p> <section style="display: inline-block; color: inherit;"> <strong>程序员内参</strong> </section> </section> </section> <section style="display: inline-block; color: inherit;"> <section class="" style="margin: 5px 1em; font-size: 1em; line-height: 1; color: rgb(107, 77, 64); border-color: rgb(107, 77, 64);"> 微信号: <p style="display: inline !important;">programmer0001</p> <span style="color: rgb(120, 172, 254);"><strong style="font-size: 1em; line-height: 1;"><p style="display: inline !important;"><br></p></strong></span> </section> <section class="" style="margin: 5px 1em; font-size: 1em; line-height: 1; color: rgb(107, 77, 64); border-color: rgb(107, 77, 64);"> <br> </section> <section style="display: inline-block; color: inherit;"> <strong><span style="color: rgb(120, 172, 254);">推荐理由:</span></strong> </section> <span style="font-size: 14px;"><strong style="color: rgb(255, 0, 0); font-size: 13px;"><span style="font-size: 14px;"></span></strong>在这里,我们分享程序员相关技术,职场生活,行业热点资讯。不定期还会分享IT趣文和趣图。这里属于我们程序员自己的生活,工作和娱乐空间。</span> <p><br></p> <section class="" style="margin: 5px 1em; font-size: 1em; line-height: 1; color: rgb(107, 77, 64); border-color: rgb(107, 77, 64);"> <span style="color: rgb(120, 172, 254);">&nbsp;▼长按下方↓↓↓二维码识别关注</span> </section> <section class="" style="margin: 5px 1em; font-size: 1em; line-height: 1; color: rgb(107, 77, 64); border-color: rgb(107, 77, 64);"> <img class="" data-ratio="0.6666666666666666" data-type="jpeg" src="/upload/8bd1607c8e6ba25be5620e6d6361f03c.jpg" style="visibility: visible !important; width:auto !important;max-width:100% !important;height:auto !important;" width="auto"> </section> </section> </blockquote>

一文了解Spring Cloud Stream体系

作者:微信小助手

<section class="xmteditor" style="display:none;" data-tools="新媒体管家" data-label="powered by xmt.cn"></section> <p style="text-align: center;"><strong style="max-width: 100%;letter-spacing: 0.544px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 16px;white-space: pre-line;background-color: rgb(255, 255, 255);text-align: right;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;color: rgb(136, 136, 136);box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></strong></p> <p style="white-space: normal;text-align: center;"><strong><span style="font-size: 14px;color: rgb(136, 136, 136);">点击蓝色“</span></strong><span style="color: rgb(0, 128, 255);"><strong><span style="font-size: 14px;">程序猿DD</span></strong></span><strong><span style="font-size: 14px;color: rgb(136, 136, 136);">”关注我哟</span></strong></p> <p style="white-space: normal;text-align: center;"><strong><span style="font-size: 14px;color: rgb(136, 136, 136);">加个“</span></strong><span style="color: rgb(0, 128, 255);"><strong><span style="font-size: 14px;">星标</span></strong></span><strong><span style="font-size: 14px;color: rgb(136, 136, 136);">”,不忘签到哦</span></strong></p> <p><br></p> <p style="text-align: left;"><span style="color: rgb(255, 41, 65);"><strong><img class="" data-ratio="0.5625" src="/upload/a41b12345b6680075c9e83dde82352a0.jpg" data-type="jpeg" data-w="1920" style="box-shadow: rgb(170, 170, 170) 0px 0px 14px 0px;border-radius: 16px;"></strong></span></p> <p style="text-align: right;"><span style="color: rgb(136, 136, 136);font-family: -apple-system, system-ui, &quot;Segoe UI&quot;, Roboto, &quot;Helvetica Neue&quot;, Helvetica, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, SimSun, sans-serif;font-size: 12px;letter-spacing: 0.16px;text-align: right;white-space: pre-line;background-color: rgb(255, 255, 255);">来源:阿里巴巴中间件</span></p> <hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"> <p style="text-align: right;"><span style="color: rgb(136, 136, 136);font-family: -apple-system, system-ui, &quot;Segoe UI&quot;, Roboto, &quot;Helvetica Neue&quot;, Helvetica, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, SimSun, sans-serif;font-size: 12px;letter-spacing: 0.16px;text-align: right;white-space: pre-line;background-color: rgb(255, 255, 255);"></span><br></p> <p style="white-space: normal;"><strong style="font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"><span style="box-sizing: border-box;font-size: 15px;">Spring Cloud Stream</span></strong><span style="font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box;font-size: 15px;">&nbsp;在&nbsp;Spring&nbsp;Cloud&nbsp;体系内用于构建高度可扩展的基于事件驱动的微服务,其目的是为了简化消息在&nbsp;Spring&nbsp;Cloud&nbsp;应用程序中的开发。</span></p> <p style="white-space: normal;line-height: 1.75em;"><br></p> <p style="white-space: normal;line-height: 1.75em;"><span style="font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box;font-size: 15px;">Spring Cloud Stream&nbsp;</span><span style="font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box;font-size: 15px;color: rgb(136, 136, 136);">(后面以 SCS 代替 Spring Cloud Stream)&nbsp;</span><span style="font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box;font-size: 15px;">本身内容很多,而且它还有很多外部的依赖,想要熟悉&nbsp;SCS,必须要先了解&nbsp;Spring&nbsp;Messaging&nbsp;和&nbsp;Spring&nbsp;Integration&nbsp;这两个项目,接下来,文章将从围绕以下三点进行展开:</span></p> <p style="white-space: normal;line-height: 1.75em;"><br></p> <ul class="ul-list list-paddingleft-2" cid="n7" mdtype="list" data-mark="*" style=""> <li><p style="line-height: 1.75em;"><span style="box-sizing: border-box;font-size: 15px;">什么是&nbsp;Spring&nbsp;Messaging;</span></p></li> <li><p style="line-height: 1.75em;"><span style="box-sizing: border-box;font-size: 15px;">什么是&nbsp;Spring&nbsp;Integration;</span></p></li> <li><p style="line-height: 1.75em;"><span style="box-sizing: border-box;font-size: 15px;">什么是&nbsp;SCS&nbsp;体系及其原理;</span></p></li> </ul> <p style="white-space: normal;box-sizing: border-box;text-align: center;line-height: 1.75em;"><br></p> <h3 cid="n22" mdtype="heading" class="md-end-block md-heading" style="margin-top: 1rem;margin-bottom: 1rem;font-weight: bold;font-size: 1.5em;box-sizing: border-box;break-after: avoid-page;break-inside: avoid;cursor: text;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;text-align: center;text-size-adjust: auto;background-color: rgb(255, 255, 255);line-height: 1.75em;"><span style="box-sizing: border-box;font-size: 18px;color: rgb(0, 122, 170);">Spring Messaging</span></h3> <hr style="white-space: normal;border-style: solid;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-color: rgba(0, 0, 0, 0.1);transform-origin: 0px 0px;transform: scale(1, 0.5);"> <p style="margin-top: 0.8em;margin-bottom: 0.8em;box-sizing: border-box;orphans: 4;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;font-size: 16px;text-size-adjust: auto;background-color: rgb(255, 255, 255);line-height: 1.75em;"><span style="box-sizing: border-box;font-size: 15px;">Spring&nbsp;Messaging&nbsp;是&nbsp;Spring&nbsp;Framework&nbsp;中的一个模块,其作用就是统一消息的编程模型。</span><br></p> <ul class="ul-list list-paddingleft-2" cid="n160" mdtype="list" data-mark="*" style=""> <li><p style="margin-bottom: 0.5rem;box-sizing: border-box;orphans: 4;white-space: pre-wrap;line-height: 1.75em;"><span style="font-size: 15px;box-sizing: border-box;">比如消息 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">Messaging</code></span><span style="font-size: 15px;box-sizing: border-box;">&nbsp;对应的模型就包括一个消息体&nbsp;Payload&nbsp;和消息头&nbsp;Header:</span></p></li> </ul> <p style="margin-top: 0.8em;margin-bottom: 0.8em;box-sizing: border-box;orphans: 4;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;font-size: 16px;text-align: center;text-size-adjust: auto;background-color: rgb(255, 255, 255);line-height: 1.75em;"><span style="box-sizing: border-box;min-width: 10px;min-height: 10px;word-break: break-all;font-family: monospace;vertical-align: top;display: inline-block;width: 800px;font-size: 15px;"><img class="" data-ratio="0.8025210084033614" src="/upload/b2aa4de011254ac2ceb7edabdfc93f36.jpg" data-type="jpeg" data-w="238" style="margin: auto;box-sizing: border-box;border-width: 0px 4px 0px 2px;border-right-style: solid;border-left-style: solid;border-right-color: transparent;border-left-color: transparent;vertical-align: middle;cursor: default;transform: translateZ(0px);display: block;"></span></p> <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n26" mdtype="fences" style="margin-top: 15px;margin-bottom: 15px;padding: 8px 4px 6px;box-sizing: border-box;overflow: visible;font-family: var(--monospace);font-size: 0.9em;break-inside: avoid;white-space: normal;background-image: inherit;background-size: inherit;background-attachment: inherit;background-origin: inherit;background-clip: inherit;background-color: rgb(248, 248, 248);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);border-radius: 3px;width: inherit;caret-color: rgb(51, 51, 51);text-size-adjust: auto;"><p style="line-height: 1.75em;"><span style="font-size: 14px;"><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">package&nbsp;org.springframework.messaging;</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">public&nbsp;interface&nbsp;Message&lt;T&gt;&nbsp;{</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">&nbsp; &nbsp; T&nbsp;getPayload();</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">&nbsp; &nbsp; MessageHeaders&nbsp;getHeaders();</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">}</span></span></p></pre> <ul class="ul-list list-paddingleft-2" cid="n27" mdtype="list" data-mark="*" style=""> <li><p style="margin-bottom: 0.5rem;box-sizing: border-box;orphans: 4;white-space: pre-wrap;line-height: 1.75em;"><span style="font-size: 15px;box-sizing: border-box;">消息通道 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">MessageChannel</code></span><span style="font-size: 15px;box-sizing: border-box;"> 用于接收消息,调用 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">send</code></span><span style="font-size: 15px;box-sizing: border-box;">&nbsp;方法可以将消息发送至该消息通道中&nbsp;:</span></p></li> </ul> <p style="margin-top: 0.8em;margin-bottom: 0.8em;box-sizing: border-box;orphans: 4;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;font-size: 16px;text-align: center;text-size-adjust: auto;background-color: rgb(255, 255, 255);line-height: 1.75em;"><span style="box-sizing: border-box;min-width: 10px;min-height: 10px;word-break: break-all;font-family: monospace;vertical-align: top;display: inline-block;width: 800px;font-size: 15px;"><img class="" data-ratio="0.15992647058823528" src="/upload/b26b0913ef5378a2fc10440009a8169c.jpg" data-type="jpeg" data-w="544" style="margin: auto;box-sizing: border-box;border-width: 0px 4px 0px 2px;border-right-style: solid;border-left-style: solid;border-right-color: transparent;border-left-color: transparent;vertical-align: middle;cursor: default;transform: translateZ(0px);display: block;"></span></p> <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n29" mdtype="fences" style="margin-top: 15px;margin-bottom: 15px;padding: 8px 4px 6px;box-sizing: border-box;overflow: visible;font-family: var(--monospace);font-size: 0.9em;break-inside: avoid;white-space: normal;background-image: inherit;background-size: inherit;background-attachment: inherit;background-origin: inherit;background-clip: inherit;background-color: rgb(248, 248, 248);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);border-radius: 3px;width: inherit;caret-color: rgb(51, 51, 51);text-size-adjust: auto;"><p style="line-height: 1.75em;"><span style="font-size: 14px;"><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">@FunctionalInterface</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">public&nbsp;interface&nbsp;MessageChannel&nbsp;{</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">&nbsp; &nbsp; long&nbsp;INDEFINITE_TIMEOUT&nbsp;=&nbsp;-1;</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">&nbsp;&nbsp;&nbsp;&nbsp;default&nbsp;boolean&nbsp;send(Message&lt;?</span><span class="cm-operator" style="font-family: var(--monospace);">&gt;&nbsp;message) {</span></span></p><p style="line-height: 1.75em;"><span style="font-size: 14px;"><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return&nbsp;send(message,&nbsp;INDEFINITE_TIMEOUT</span><span style="font-family: var(--monospace);">);</span></span></p><p style="line-height: 1.75em;"><span style="font-size: 14px;"><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">&nbsp; &nbsp; &nbsp;}</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;boolean&nbsp;send(Message&lt;?&gt;&nbsp;message,&nbsp;long&nbsp;timeout);</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">}</span></span></p></pre> <h5 cid="n30" mdtype="heading" class="md-end-block md-heading" style="margin-top: 1rem;margin-bottom: 1rem;font-weight: bold;font-size: 1em;box-sizing: border-box;break-after: avoid-page;break-inside: avoid;cursor: text;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;text-size-adjust: auto;background-color: rgb(255, 255, 255);line-height: 1.75em;"><span style="box-sizing: border-box;font-size: 15px;color: rgb(0, 122, 170);">消息通道里的消息如何被消费呢?&nbsp;</span></h5> <ul class="ul-list list-paddingleft-2" cid="n154" mdtype="list" data-mark="*" style=""> <li><p style="margin-bottom: 0.5rem;box-sizing: border-box;orphans: 4;white-space: pre-wrap;line-height: 1.75em;"><span style="font-size: 15px;box-sizing: border-box;">由消息通道的子接口可订阅的消息通道 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">SubscribableChannel </code></span><span style="font-size: 15px;box-sizing: border-box;">实现,被 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">MessageHandler</code></span><span style="font-size: 15px;box-sizing: border-box;">&nbsp;消息处理器所订阅:</span></p></li> </ul> <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n31" mdtype="fences" style="margin-top: 15px;margin-bottom: 15px;padding: 8px 4px 6px;box-sizing: border-box;overflow: visible;font-family: var(--monospace);font-size: 0.9em;break-inside: avoid;white-space: normal;background-image: inherit;background-size: inherit;background-attachment: inherit;background-origin: inherit;background-clip: inherit;background-color: rgb(248, 248, 248);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);border-radius: 3px;width: inherit;caret-color: rgb(51, 51, 51);text-size-adjust: auto;"><p style="line-height: 1.75em;"><span style="font-size: 14px;"><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">public&nbsp;interface&nbsp;SubscribableChannel&nbsp;extends&nbsp;MessageChannel&nbsp;{</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">&nbsp; &nbsp; boolean&nbsp;subscribe(MessageHandler&nbsp;handler);</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">&nbsp; &nbsp; boolean&nbsp;unsubscribe(MessageHandler&nbsp;handler);</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">}</span></span></p></pre> <ul class="ul-list list-paddingleft-2" cid="n32" mdtype="list" data-mark="*" style=""> <li><p style="margin-bottom: 0.5rem;box-sizing: border-box;orphans: 4;white-space: pre-wrap;line-height: 1.75em;"><span style="font-size: 15px;box-sizing: border-box;">由</span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">MessageHandler</code></span><span style="font-size: 15px;box-sizing: border-box;">&nbsp;真正地消费/处理消息:</span></p></li> </ul> <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n33" mdtype="fences" style="margin-top: 15px;margin-bottom: 15px;padding: 8px 4px 6px;box-sizing: border-box;overflow: visible;font-family: var(--monospace);font-size: 0.9em;break-inside: avoid;white-space: normal;background-image: inherit;background-size: inherit;background-attachment: inherit;background-origin: inherit;background-clip: inherit;background-color: rgb(248, 248, 248);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);border-radius: 3px;width: inherit;caret-color: rgb(51, 51, 51);text-size-adjust: auto;"><p style="line-height: 1.75em;"><span style="font-size: 14px;"><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">@FunctionalInterface</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">public&nbsp;interface&nbsp;MessageHandler&nbsp;{</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;handleMessage(Message&lt;?&gt;&nbsp;message)&nbsp;throws&nbsp;MessagingException;</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">}</span></span></p></pre> <h5 cid="n34" mdtype="heading" class="md-end-block md-heading" style="margin-top: 1rem;margin-bottom: 1rem;font-weight: bold;font-size: 1em;box-sizing: border-box;break-after: avoid-page;break-inside: avoid;cursor: text;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;text-size-adjust: auto;background-color: rgb(255, 255, 255);line-height: 1.75em;"><span style="box-sizing: border-box;font-size: 15px;color: rgb(0, 122, 170);">Spring&nbsp;Messaging&nbsp;内部在消息模型的基础上衍生出了其它的一些功能,如:</span></h5> <p style="margin-bottom: 0.5rem;box-sizing: border-box;orphans: 4;white-space: pre-wrap;line-height: 1.75em;"><span style="font-size: 15px;box-sizing: border-box;">1.&nbsp;消息接收参数及返回值处理:消息接收参数处理器&nbsp;</span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">HandlerMethodArgumentResolver</code></span><span style="font-size: 15px;box-sizing: border-box;"> 配合 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">@Header, @Payload</code></span><span style="font-size: 15px;box-sizing: border-box;">&nbsp;等注解使用;消息接收后的返回值处理器&nbsp;</span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">HandlerMethodReturnValueHandler</code></span><span style="font-size: 15px;box-sizing: border-box;"> 配合 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">@SendTo</code></span><span style="font-size: 15px;box-sizing: border-box;">&nbsp;注解使用;</span></p> <p style="margin-bottom: 0.5rem;box-sizing: border-box;orphans: 4;white-space: pre-wrap;line-height: 1.75em;"><span style="font-size: 15px;box-sizing: border-box;">2. 消息体内容转换器 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">MessageConverter</code></span><span style="font-size: 15px;box-sizing: border-box;">;</span></p> <p style="margin-bottom: 0.5rem;box-sizing: border-box;orphans: 4;white-space: pre-wrap;line-height: 1.75em;"><span style="font-size: 15px;box-sizing: border-box;">3. 统一抽象的消息发送模板 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">AbstractMessageSendingTemplate</code></span><span style="font-size: 15px;box-sizing: border-box;">;</span></p> <p style="margin-bottom: 0.5rem;box-sizing: border-box;orphans: 4;white-space: pre-wrap;line-height: 1.75em;"><span style="font-size: 15px;box-sizing: border-box;">4. 消息通道拦截器 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">ChannelInterceptor</code></span><span style="font-size: 15px;box-sizing: border-box;">;</span></p> <p cid="n46" mdtype="paragraph" class="md-end-block md-p" style="margin-top: 0.8em;margin-bottom: 0.8em;box-sizing: border-box;orphans: 4;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;font-size: 16px;text-align: start;text-size-adjust: auto;background-color: rgb(255, 255, 255);"><br></p> <h3 cid="n47" mdtype="heading" class="md-end-block md-heading" style="margin-top: 1rem;margin-bottom: 1rem;font-weight: bold;font-size: 1.5em;box-sizing: border-box;break-after: avoid-page;break-inside: avoid;cursor: text;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;text-align: center;text-size-adjust: auto;background-color: rgb(255, 255, 255);line-height: 1.75em;"><span style="box-sizing: border-box;font-size: 18px;color: rgb(0, 122, 170);">Spring Integration</span></h3> <hr style="white-space: normal;border-style: solid;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-color: rgba(0, 0, 0, 0.1);transform-origin: 0px 0px;transform: scale(1, 0.5);"> <p style="margin-top: 0.8em;margin-bottom: 0.8em;box-sizing: border-box;orphans: 4;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;font-size: 16px;text-size-adjust: auto;background-color: rgb(255, 255, 255);line-height: 1.75em;"><span style="box-sizing: border-box;font-size: 15px;">Spring Integration</span><span style="font-size: 15px;box-sizing: border-box;"> 提供了 Spring 编程模型的扩展用来支持企业集成模式(<span md-inline="plain" class="md-plain" style="box-sizing: border-box;">Enterprise Integration Patterns</span>),是对&nbsp;Spring&nbsp;Messaging&nbsp;的扩展。</span></p> <p style="margin-top: 0.8em;margin-bottom: 0.8em;box-sizing: border-box;orphans: 4;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;font-size: 16px;text-size-adjust: auto;background-color: rgb(255, 255, 255);line-height: 1.75em;"><span style="font-size: 15px;box-sizing: border-box;">它提出了不少新的概念,包括消息路由 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">MessageRoute</code></span><span style="font-size: 15px;box-sizing: border-box;">、消息分发 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">MessageDispatcher</code></span><span style="font-size: 15px;box-sizing: border-box;">、消息过滤 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">Filter</code></span><span style="font-size: 15px;box-sizing: border-box;">、消息转换 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">Transformer</code></span><span style="font-size: 15px;box-sizing: border-box;">、消息聚合 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">Aggregator</code></span><span style="font-size: 15px;box-sizing: border-box;">、消息分割 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">Splitter </code></span><span style="font-size: 15px;box-sizing: border-box;">等等。同时还提供了&nbsp;</span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">MessageChannel</code></span><span style="font-size: 15px;box-sizing: border-box;"> 和</span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">MessageHandler </code></span><span style="font-size: 15px;box-sizing: border-box;">的实现,分别包括 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">DirectChannel、ExecutorChannel、PublishSubscribeChannel</code></span><span style="font-size: 15px;box-sizing: border-box;"> 和</span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">MessageFilter、ServiceActivatingHandler、MethodInvokingSplitter</code></span><span style="font-size: 15px;box-sizing: border-box;">&nbsp;等内容。</span><br></p> <h5 cid="n50" mdtype="heading" class="md-end-block md-heading" style="margin-top: 1rem;margin-bottom: 1rem;font-weight: bold;font-size: 1em;box-sizing: border-box;break-after: avoid-page;break-inside: avoid;cursor: text;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;text-size-adjust: auto;background-color: rgb(255, 255, 255);line-height: 1.75em;"><span style="box-sizing: border-box;font-size: 15px;color: rgb(0, 122, 170);">这里为大家介绍几种消息的处理方式:</span></h5> <ul class="ul-list list-paddingleft-2" cid="n51" mdtype="list" data-mark="*" style=""> <li><p style="margin-bottom: 0.5rem;box-sizing: border-box;orphans: 4;white-space: pre-wrap;line-height: 1.75em;"><span style="box-sizing: border-box;font-size: 15px;">消息的分割:</span></p></li> </ul> <p style="white-space: normal;text-align: center;line-height: 1.75em;"><img class="rich_pages" data-copyright="0" data-ratio="0.3260437375745527" data-s="300,640" src="/upload/31db805bfba90a7587cbfc532a557292.png" data-type="png" data-w="1006"></p> <ul class="ul-list list-paddingleft-2" cid="n53" mdtype="list" data-mark="*" style=""> <li><p style="margin-bottom: 0.5rem;box-sizing: border-box;orphans: 4;white-space: pre-wrap;line-height: 1.75em;"><span style="box-sizing: border-box;font-size: 15px;">消息的聚合:</span></p></li> </ul> <p style="white-space: normal;text-align: center;line-height: 1.75em;"><img class="rich_pages" data-copyright="0" data-ratio="0.3606194690265487" data-s="300,640" src="/upload/ec6eebb33d4668cba7bb7618136ac4b3.png" data-type="png" data-w="904"></p> <p style="white-space: normal;"><br></p> <ul class="ul-list list-paddingleft-2" cid="n55" mdtype="list" data-mark="*" style=""> <li><p style="margin-bottom: 0.5rem;box-sizing: border-box;orphans: 4;white-space: pre-wrap;line-height: 1.75em;"><span style="box-sizing: border-box;font-size: 15px;">消息的过滤:</span></p></li> </ul> <p style="white-space: normal;text-align: center;line-height: 1.75em;"><img class="rich_pages" data-copyright="0" data-ratio="0.19696969696969696" data-s="300,640" src="/upload/d1b774cbcd5fbfd75dc952624e9c606d.png" data-type="png" data-w="1188"></p> <ul class="ul-list list-paddingleft-2" cid="n55" mdtype="list" data-mark="*" style=""> <li><p style="margin-bottom: 0.5rem;box-sizing: border-box;orphans: 4;white-space: pre-wrap;line-height: 1.75em;"><span style="box-sizing: border-box;font-size: 15px;">消息的分发:</span></p></li> </ul> <p style="white-space: normal;text-align: center;line-height: 1.75em;"><img class="rich_pages" data-copyright="0" data-ratio="0.6718146718146718" data-s="300,640" src="/upload/5bdfdbfae36491b960e56cb84fa39873.png" data-type="png" data-w="1036"></p> <p style="white-space: normal;"><br></p> <h5 cid="n59" mdtype="heading" class="md-end-block md-heading" style="margin-top: 1rem;margin-bottom: 1rem;font-weight: bold;font-size: 1em;box-sizing: border-box;break-after: avoid-page;break-inside: avoid;cursor: text;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;text-size-adjust: auto;background-color: rgb(255, 255, 255);line-height: 1.75em;"><span style="box-sizing: border-box;font-size: 15px;color: rgb(0, 122, 170);">接下来,我们以一个最简单的例子来尝试一下&nbsp;Spring&nbsp;Integration:</span></h5> <p style="white-space: normal;"><span style="font-size: 15px;box-sizing: border-box;">这段代码解释为:</span></p> <p style="white-space: normal;">&nbsp;</p> <p style="padding: 13px;white-space: normal;background: rgb(250, 250, 250);border-width: initial;border-style: none;border-color: initial;"><span style="font-size: 14px;"><span style="line-height: 16.1px;">SubscribableChannel messageChannel =new DirectChannel(); // 1</span><br><br><span style="line-height: 16.1px;">messageChannel.subscribe(msg-&gt; { // 2</span><br><span style="line-height: 16.1px;">&nbsp;System.out.println("receive:&nbsp;"&nbsp;+msg.getPayload());</span><br><span style="line-height: 16.1px;">});</span><br><br><span style="line-height: 16.1px;">messageChannel.send(MessageBuilder.withPayload("msgfrom alibaba").build()); // 3</span></span></p> <p style="white-space: normal;"><br></p> <p style="margin-bottom: 0.5rem;box-sizing: border-box;orphans: 4;white-space: pre-wrap;line-height: 1.75em;"><span style="font-size: 15px;box-sizing: border-box;">1. 构造一个可订阅的消息通道 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">messageChannel</code></span><span style="font-size: 15px;box-sizing: border-box;">;</span></p> <p style="margin-bottom: 0.5rem;box-sizing: border-box;orphans: 4;white-space: pre-wrap;line-height: 1.75em;"><span style="font-size: 15px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">2. 使用 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">MessageHandler</code></span><span style="font-size: 15px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">&nbsp;去消费这个消息通道里的消息;</span></p> <p style="margin-bottom: 0.5rem;box-sizing: border-box;orphans: 4;white-space: pre-wrap;line-height: 1.75em;"><span style="font-size: 15px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">3. 发送一条消息到这个消息通道,消息最终被消息通道里的 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">MessageHandler</code></span><span style="font-size: 15px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">&nbsp;所消费。</span></p> <p style="margin-bottom: 0.5rem;box-sizing: border-box;orphans: 4;white-space: pre-wrap;line-height: 1.75em;"><span style="font-size: 15px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">最后控制台打印出:&nbsp;</span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">receive:&nbsp;msg&nbsp;from&nbsp;alibaba</code></span><span style="font-size: 15px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">;</span></p> <p style="margin-top: 0.8em;margin-bottom: 0.8em;box-sizing: border-box;orphans: 4;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;font-size: 16px;text-size-adjust: auto;background-color: rgb(255, 255, 255);line-height: 1.75em;"><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">DirectChannel</code></span><span style="font-size: 15px;box-sizing: border-box;"> 内部有个 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">UnicastingDispatcher</code></span><span style="font-size: 15px;box-sizing: border-box;"> 类型的消息分发器,会分发到对应的消息通道 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">MessageChannel</code></span><span style="font-size: 15px;box-sizing: border-box;"> 中,从名字也可以看出来,</span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">UnicastingDispatcher</code></span><span style="font-size: 15px;box-sizing: border-box;">&nbsp;是个单播的分发器,只能选择一个消息通道。那么如何选择呢?&nbsp;内部提供了&nbsp;</span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">LoadBalancingStrategy</code></span><span style="font-size: 15px;box-sizing: border-box;">&nbsp;负载均衡策略,默认只有轮询的实现,可以进行扩展。</span></p> <p style="margin-top: 0.8em;margin-bottom: 0.8em;box-sizing: border-box;orphans: 4;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;font-size: 16px;text-size-adjust: auto;background-color: rgb(255, 255, 255);line-height: 1.75em;"><span style="font-size: 15px;box-sizing: border-box;">我们对上段代码做一点修改,使用多个 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">MessageHandler</code></span><span style="font-size: 15px;box-sizing: border-box;">&nbsp;去处理消息:</span></p> <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n72" mdtype="fences" style="margin-top: 15px;margin-bottom: 15px;padding: 8px 4px 6px;box-sizing: border-box;overflow: visible;font-family: var(--monospace);font-size: 0.9em;break-inside: avoid;white-space: normal;background-image: inherit;background-size: inherit;background-attachment: inherit;background-origin: inherit;background-clip: inherit;background-color: rgb(248, 248, 248);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);border-radius: 3px;width: inherit;caret-color: rgb(51, 51, 51);text-size-adjust: auto;"><p style="line-height: 1.75em;"><span style="font-size: 14px;"><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">SubscribableChannel&nbsp;messageChannel&nbsp;=&nbsp;new&nbsp;DirectChannel();</span><br><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">messageChannel.subscribe(msg&nbsp;-&gt;&nbsp;{</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("receive1:&nbsp;"&nbsp;+&nbsp;msg.getPayload());</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">});</span><br><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">messageChannel.subscribe(msg&nbsp;-&gt;&nbsp;{</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("receive2:&nbsp;"&nbsp;+&nbsp;msg.getPayload());</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">});</span><br><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">messageChannel.send(MessageBuilder.withPayload("msg from alibaba").build());</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">messageChannel.send(MessageBuilder.withPayload("msg from alibaba").build());</span></span></p></pre> <p style="margin-top: 0.8em;margin-bottom: 0.8em;box-sizing: border-box;orphans: 4;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;font-size: 16px;text-size-adjust: auto;background-color: rgb(255, 255, 255);line-height: 1.75em;"><span style="font-size: 15px;box-sizing: border-box;">由于 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">DirectChannel</code></span><span style="font-size: 15px;box-sizing: border-box;"> 内部的消息分发器是 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">UnicastingDispatcher</code></span><span style="font-size: 15px;box-sizing: border-box;"> 单播的方式,并且采用轮询的负载均衡策略,所以这里两次的消费分别对应这两个 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">MessageHandler</code></span><span style="font-size: 15px;box-sizing: border-box;">。控制台打印出:</span></p> <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n74" mdtype="fences" style="margin-top: 15px;margin-bottom: 15px;padding: 8px 4px 6px;box-sizing: border-box;overflow: visible;font-family: var(--monospace);font-size: 0.9em;break-inside: avoid;white-space: normal;background-image: inherit;background-size: inherit;background-attachment: inherit;background-origin: inherit;background-clip: inherit;background-color: rgb(248, 248, 248);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);border-radius: 3px;width: inherit;caret-color: rgb(51, 51, 51);text-size-adjust: auto;"><p style="line-height: 1.75em;"><span style="font-size: 15px;"><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">receive1:&nbsp;msg&nbsp;from&nbsp;alibaba</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">receive2:&nbsp;msg&nbsp;from&nbsp;alibaba</span></span></p></pre> <p style="margin-top: 0.8em;margin-bottom: 0.8em;box-sizing: border-box;orphans: 4;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;font-size: 16px;text-size-adjust: auto;background-color: rgb(255, 255, 255);line-height: 1.75em;"><span style="font-size: 15px;box-sizing: border-box;">既然存在单播的消息分发器 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">UnicastingDispatcher</code></span><span style="font-size: 15px;box-sizing: border-box;">,必然也会存在广播的消息分发器,那就是 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">BroadcastingDispatcher</code></span><span style="font-size: 15px;box-sizing: border-box;">,它被 </span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">PublishSubscribeChannel</code></span><span style="font-size: 15px;box-sizing: border-box;">&nbsp;这个消息通道所使用。广播消息分发器会把消息分发给所有的&nbsp;</span><span style="box-sizing: border-box;font-size: 14px;"><code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">MessageHandler</code></span><span style="font-size: 15px;box-sizing: border-box;">:</span></p> <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n76" mdtype="fences" style="margin-top: 15px;margin-bottom: 15px;padding: 8px 4px 6px;box-sizing: border-box;overflow: visible;font-family: var(--monospace);font-size: 0.9em;break-inside: avoid;white-space: normal;background-image: inherit;background-size: inherit;background-attachment: inherit;background-origin: inherit;background-clip: inherit;background-color: rgb(248, 248, 248);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);border-radius: 3px;width: inherit;caret-color: rgb(51, 51, 51);text-size-adjust: auto;"><p style="line-height: 1.75em;"><span style="font-size: 14px;"><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">SubscribableChannel&nbsp;messageChannel&nbsp;=&nbsp;new&nbsp;PublishSubscribeChannel();</span><br><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">messageChannel.subscribe(msg&nbsp;-&gt;&nbsp;{</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("receive1:&nbsp;"&nbsp;+&nbsp;msg.getPayload());</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">});</span><br><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">messageChannel.subscribe(msg&nbsp;-&gt;&nbsp;{</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("receive2:&nbsp;"&nbsp;+&nbsp;msg.getPayload());</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">});</span><br><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">messageChannel.send(MessageBuilder.withPayload("msg from alibaba").build());</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">messageChannel.send(MessageBuilder.withPayload("msg from alibaba").build());</span></span></p></pre> <p style="margin-top: 0.8em;margin-bottom: 0.8em;box-sizing: border-box;orphans: 4;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;font-size: 16px;text-size-adjust: auto;background-color: rgb(255, 255, 255);line-height: 1.75em;"><span style="font-size: 15px;box-sizing: border-box;">发送两个消息,都被所有的 <code style="padding-right: 2px;padding-left: 2px;box-sizing: border-box;font-family: var(--monospace);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;font-size: 0.9em;">MessageHandler</code>&nbsp;所消费。控制台打印:</span></p> <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n78" mdtype="fences" style="margin-top: 15px;margin-bottom: 15px;padding: 8px 4px 6px;box-sizing: border-box;overflow: visible;font-family: var(--monospace);font-size: 0.9em;break-inside: avoid;white-space: normal;background-image: inherit;background-size: inherit;background-attachment: inherit;background-origin: inherit;background-clip: inherit;background-color: rgb(248, 248, 248);border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);border-radius: 3px;width: inherit;caret-color: rgb(51, 51, 51);text-size-adjust: auto;"><p style="line-height: 1.75em;"><span style="padding-right: 0.1px;box-sizing: border-box;font-size: 14px;">r</span><span style="font-size: 14px;"><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">eceive1:&nbsp;msg&nbsp;from&nbsp;alibaba</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">receive2:&nbsp;msg&nbsp;from&nbsp;alibaba</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">receive1:&nbsp;msg&nbsp;from&nbsp;alibaba</span><br><span role="presentation" style="padding-right: 0.1px;box-sizing: border-box;">receive2:&nbsp;msg&nbsp;from&nbsp;alibaba</span></span></p></pre> <p cid="n79" mdtype="paragraph" class="md-end-block md-p" style="margin-top: 0.8em;margin-bottom: 0.8em;box-sizing: border-box;orphans: 4;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;font-size: 16px;text-align: start;text-size-adjust: auto;background-color: rgb(255, 255, 255);"><br></p> <h3 cid="n80" mdtype="heading" class="md-end-block md-heading" style="margin-top: 1rem;margin-bottom: 1rem;font-weight: bold;font-size: 1.5em;box-sizing: border-box;break-after: avoid-page;break-inside: avoid;cursor: text;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;text-align: center;text-size-adjust: auto;background-color: rgb(255, 255, 255);line-height: 1.75em;"><span style="box-sizing: border-box;font-size: 18px;color: rgb(0, 122, 170);">Spring Cloud Stream</span></h3> <hr style="white-space: normal;border-style: solid;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-color: rgba(0, 0, 0, 0.1);transform-origin: 0px 0px;transform: scale(1, 0.5);"> <p style="margin-top: 0.8em;margin-bottom: 0.8em;box-sizing: border-box;orphans: 4;white-space: pre-wrap;width: inherit;caret-color: rgb(51, 51, 51);font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&

这份阿里云 Redis 的开发规范,建议收藏!

作者:微信小助手

<p style="font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-size-adjust: auto;font-size: 15px;word-spacing: 2px;text-align: center;" data-mpa-powered-by="yiban.io"><span style="color: rgb(136, 136, 136);font-size: 14px;">点击蓝色“</span><span style="font-size: 14px;color: rgb(0, 128, 255);">架构文摘</span><span style="color: rgb(136, 136, 136);font-size: 14px;">”关注我哟</span></p> <p style="margin-bottom: 10px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-size-adjust: auto;font-size: 15px;word-spacing: 2px;text-align: center;"><span style="font-size: 14px;color: rgb(136, 136, 136);">加个“</span><span style="color: rgb(0, 128, 255);font-size: 14px;">星标</span><span style="font-size: 14px;color: rgb(136, 136, 136);">”,每天上午 09:25,干货推送!</span></p> <p style="margin-bottom: 10px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-size-adjust: auto;font-size: 15px;word-spacing: 2px;text-align: center;"><span style="font-size: 14px;color: rgb(136, 136, 136);"><br></span></p> <section class="output_wrapper" style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">本文主要介绍在使用阿里云Redis的开发规范,从下面几个方面进行说明。</p> <ul style="" class=" list-paddingleft-2"> <li><p><span style="font-size: inherit;color: inherit;line-height: inherit;">键值设计</span></p></li> <li><p><span style="font-size: inherit;color: inherit;line-height: inherit;">命令使用</span></p></li> <li><p><span style="font-size: inherit;color: inherit;line-height: inherit;">客户端使用</span></p></li> <li><p><span style="font-size: inherit;color: inherit;line-height: inherit;">相关工具</span></p></li> </ul> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">通过本文的介绍可以减少使用Redis过程带来的问题。</p> <h3 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.3em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">一、键值设计</span></h3> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">1、key名设计</span></h4> <h5 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">可读性和可管理性</span></h5> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">以业务名(或数据库名)为前缀(防止key冲突),用冒号分隔,比如业务名:表名:id</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs css" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">ugc</span><span class="hljs-selector-pseudo" style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">:video</span><span class="hljs-selector-pseudo" style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">:1</span><br></code></pre> <h6 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">简洁性</span></h6> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">保证语义的前提下,控制key的长度,当key较多时,内存占用也不容忽视,例如:</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs ruby" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span class="hljs-symbol" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">user:</span>{uid}<span class="hljs-symbol" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">:friends</span><span class="hljs-symbol" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">:messages</span><span class="hljs-symbol" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">:</span>{mid}<br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">简化为:</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs ruby" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span class="hljs-symbol" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">u:</span>{uid}<span class="hljs-symbol" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">:fr</span><span class="hljs-symbol" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">:m</span><span class="hljs-symbol" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">:</span>{mid}<br></code></pre> <h5 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">不要包含特殊字符</span></h5> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">反例:包含空格、换行、单双引号以及其他转义字符</p> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">2、value设计</span></h4> <h5 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">拒绝bigkey</span></h5> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">防止网卡流量、慢查询,string类型控制在10KB以内,hash、list、set、zset元素个数不要超过5000。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;"><strong style="font-size: inherit;color: inherit;line-height: inherit;">反例:一个包含200万个元素的list。</strong></p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">非字符串的bigkey,不要使用del删除,使用hscan、sscan、zscan方式渐进式删除,同时要注意防止bigkey过期时间自动删除问题(例如一个200万的zset设置1小时过期,会触发del操作,造成阻塞,而且该操作不会不出现在慢查询中(latency可查)),查找方法和删除方法</p> <h5 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">选择适合的数据类型</span></h5> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">例如:实体类型(要合理控制和使用数据结构内存编码优化配置,例如ziplist,但也要注意节省内存和性能之间的平衡)</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">反例:</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs sql" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">set</span>&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">user</span>:<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">1</span>:<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">name</span>&nbsp;tom<br><span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">set</span>&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">user</span>:<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">1</span>:age&nbsp;<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">19</span><br><span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">set</span>&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">user</span>:<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">1</span>:favor&nbsp;football<br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">正例:</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs css" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">hmset</span>&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">user</span><span class="hljs-selector-pseudo" style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">:1</span>&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">name</span>&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">tom</span>&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">age</span>&nbsp;19&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">favor</span>&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">football</span><br></code></pre> <h5 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">控制key的生命周期</span></h5> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">redis不是垃圾桶,建议使用<code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">expire</code>设置过期时间(条件允许可以打散过期时间,防止集中过期),不过期的数据重点关注<code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">idletime</code>。</p> <h3 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.3em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">二、命令使用</span></h3> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">1、O(N)命令关注N的数量</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">例如hgetall、lrange、smembers、zrange、sinter等并非不能使用,但是需要明确N的值。有遍历的需求可以使用hscan、sscan、zscan代替。</p> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">2、禁用命令</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">禁止线上使用keys、flushall、flushdb等,通过redis的rename机制禁掉命令,或者使用scan的方式渐进式处理。</p> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">3、合理使用select</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">redis的多数据库较弱,使用数字进行区分,很多客户端支持较差,同时多业务用多数据库实际还是单线程处理,会有干扰。</p> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">4、使用批量操作提高效率</span></h4> <ul style="" class=" list-paddingleft-2"> <li><p><span style="font-size: inherit;color: inherit;line-height: inherit;">原生命令:例如mget、mset。</span></p></li> <li><p><span style="font-size: inherit;color: inherit;line-height: inherit;">非原生命令:可以使用pipeline提高效率。</span></p></li> </ul> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">但要注意控制一次批量操作的元素个数(例如500以内,实际也和元素字节数有关)。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">注意两者不同:</p> <ul style="" class=" list-paddingleft-2"> <li><p><span style="font-size: inherit;color: inherit;line-height: inherit;">原生是原子操作,pipeline是非原子操作。</span></p></li> <li><p><span style="font-size: inherit;color: inherit;line-height: inherit;">pipeline可以打包不同的命令,原生做不到</span></p></li> <li><p><span style="font-size: inherit;color: inherit;line-height: inherit;">pipeline需要客户端和服务端同时支持。</span></p></li> </ul> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">5、不建议过多使用Redis事务功能</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">Redis的事务功能较弱(不支持回滚),而且集群版本(自研和官方)要求一次事务操作的key必须在一个slot上(可以使用hashtag功能解决)</p> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">6、Redis集群版本在使用Lua上有特殊要求</span></h4> <ul style="" class=" list-paddingleft-2"> <li><p>所有key都应该由 KEYS 数组来传递,<code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">redis.call/pcall</code> 里面调用的redis命令,key的位置,必须是<code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">KEYS array</code>, 否则直接返回error,"-ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS arrayrn"</p></li> <li><p><span style="font-size: inherit;color: inherit;line-height: inherit;">所有key,必须在1个slot上,否则直接返回error, "-ERR eval/evalsha command keys must in same slotrn"</span></p></li> </ul> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">7、monitor命令</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">必要情况下使用<code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">monitor</code>命令时,要注意不要长时间使用。</p> <h3 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.3em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">三、客户端使用</span></h3> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">1、避免多个应用使用一个Redis实例</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">不相干的业务拆分,公共数据做服务化。</p> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">2、使用连接池</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">可以有效控制连接,同时提高效率,标准使用方式:</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs php" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;">执行命令如下:<br>Jedis&nbsp;jedis&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">null</span>;<br><span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">try</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;jedis&nbsp;=&nbsp;jedisPool.getResource();<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment" style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//具体的命令</span><br>&nbsp;&nbsp;&nbsp;&nbsp;jedis.executeCommand()<br>}&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">catch</span>&nbsp;(<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Exception</span>&nbsp;e)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;logger.error(<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"op&nbsp;key&nbsp;{}&nbsp;error:&nbsp;"</span>&nbsp;+&nbsp;e.getMessage(),&nbsp;key,&nbsp;e);<br>}&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">finally</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment" style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//注意这里不是关闭连接,在JedisPool模式下,Jedis会被归还给资源池。</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;(jedis&nbsp;!=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">null</span>)&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jedis.close();<br>}<br></code></pre> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">3、熔断功能</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">高并发下建议客户端添加熔断功能(例如netflix hystrix)</p> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">4、合理的加密</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">设置合理的密码,如有必要可以使用SSL加密访问(阿里云Redis支持)</p> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">5、淘汰策略</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">根据自身业务类型,选好maxmemory-policy(最大内存淘汰策略),设置好过期时间。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">默认策略是volatile-lru,即超过最大内存后,在过期键中使用lru算法进行key的剔除,保证不过期数据不被删除,但是可能会出现OOM问题。</p> <h5 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">其他策略如下</span></h5> <ul style="" class=" list-paddingleft-2"> <li><p><code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">allkeys-lru</code>:根据LRU算法删除键,不管数据有没有设置超时属性,直到腾出足够空间为止。</p></li> <li><p><code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">allkeys-random</code>:随机删除所有键,直到腾出足够空间为止。</p></li> <li><p><code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">volatile-random</code>:随机删除过期键,直到腾出足够空间为止。</p></li> <li><p><code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">volatile-ttl</code>:根据键值对象的ttl属性,删除最近将要过期数据。如果没有,回退到noeviction策略。</p></li> <li><p><code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">noeviction</code>:不会剔除任何数据,拒绝所有写入操作并返回客户端错误信息"(error) OOM command not allowed when used memory",此时Redis只响应读操作。</p></li> </ul> <h3 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.3em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">四、相关工具</span></h3> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">1、数据同步</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">redis间数据同步可以使用:<code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">redis-port</code></p> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">2、热点key寻找</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">内部实现使用monitor,所以建议短时间使用facebook的redis-faina 阿里云Redis已经在内核层面解决热点key问题</p> <h3 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.3em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">五、删除bigkey</span></h3> <ol style="" class=" list-paddingleft-2"> <li><p><span style="font-size: inherit;color: inherit;line-height: inherit;">下面操作可以使用pipeline加速。</span></p></li> <li><p><span style="font-size: inherit;color: inherit;line-height: inherit;">redis 4.0已经支持key的异步删除。</span></p></li> </ol> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">1. Hash删除: hscan + hdel</span></h4> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs dart" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;">public&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;delBigHash(<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&nbsp;host,&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;port,&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&nbsp;password,&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&nbsp;bigHashKey)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;Jedis&nbsp;jedis&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;Jedis(host,&nbsp;port);<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;(password&nbsp;!=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">null</span>&nbsp;&amp;&amp;&nbsp;!<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">""</span>.equals(password))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jedis.auth(password);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;ScanParams&nbsp;scanParams&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;ScanParams().count(<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">100</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&nbsp;cursor&nbsp;=&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"0"</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">do</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ScanResult&lt;Entry&lt;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>,&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&gt;&gt;&nbsp;scanResult&nbsp;=&nbsp;jedis.hscan(bigHashKey,&nbsp;cursor,&nbsp;scanParams);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">List</span>&lt;Entry&lt;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>,&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&gt;&gt;&nbsp;entryList&nbsp;=&nbsp;scanResult.getResult();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;(entryList&nbsp;!=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">null</span>&nbsp;&amp;&amp;&nbsp;!entryList.isEmpty())&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">for</span>&nbsp;(Entry&lt;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>,&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&gt;&nbsp;entry&nbsp;:&nbsp;entryList)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jedis.hdel(bigHashKey,&nbsp;entry.getKey());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cursor&nbsp;=&nbsp;scanResult.getStringCursor();<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">while</span>&nbsp;(!<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"0"</span>.equals(cursor));<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment" style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//删除bigkey</span><br>&nbsp;&nbsp;&nbsp;&nbsp;jedis.del(bigHashKey);<br>}<br></code></pre> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">2. List删除: ltrim</span></h4> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs cs" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span class="hljs-function" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;"><span class="hljs-keyword" style="font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;<span class="hljs-title" style="font-size: inherit;line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">delBigList</span>(<span class="hljs-params" style="font-size: inherit;line-height: inherit;color: rgb(255, 152, 35);overflow-wrap: inherit !important;word-break: inherit !important;">String&nbsp;host,&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;port,&nbsp;String&nbsp;password,&nbsp;String&nbsp;bigListKey</span>)&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;Jedis&nbsp;jedis&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;Jedis(host,&nbsp;port);<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;(password&nbsp;!=&nbsp;<span class="hljs-literal" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">null</span>&nbsp;&amp;&amp;&nbsp;!<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">""</span>.<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">equals</span>(password))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jedis.auth(password);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">long</span>&nbsp;llen&nbsp;=&nbsp;jedis.llen(bigListKey);<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;counter&nbsp;=&nbsp;<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">0</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;left&nbsp;=&nbsp;<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">100</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">while</span>&nbsp;(counter&nbsp;&lt;&nbsp;llen)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment" style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//每次从左侧截掉100个</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jedis.ltrim(bigListKey,&nbsp;left,&nbsp;llen);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;counter&nbsp;+=&nbsp;left;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment" style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//最终删除key</span><br>&nbsp;&nbsp;&nbsp;&nbsp;jedis.del(bigListKey);<br>}<br></code></pre> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">3. Set删除: sscan + srem</span></h4> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs dart" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;">public&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;delBigSet(<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&nbsp;host,&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;port,&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&nbsp;password,&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&nbsp;bigSetKey)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;Jedis&nbsp;jedis&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;Jedis(host,&nbsp;port);<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;(password&nbsp;!=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">null</span>&nbsp;&amp;&amp;&nbsp;!<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">""</span>.equals(password))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jedis.auth(password);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;ScanParams&nbsp;scanParams&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;ScanParams().count(<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">100</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&nbsp;cursor&nbsp;=&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"0"</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">do</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ScanResult&lt;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&gt;&nbsp;scanResult&nbsp;=&nbsp;jedis.sscan(bigSetKey,&nbsp;cursor,&nbsp;scanParams);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">List</span>&lt;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&gt;&nbsp;memberList&nbsp;=&nbsp;scanResult.getResult();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;(memberList&nbsp;!=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">null</span>&nbsp;&amp;&amp;&nbsp;!memberList.isEmpty())&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">for</span>&nbsp;(<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&nbsp;member&nbsp;:&nbsp;memberList)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jedis.srem(bigSetKey,&nbsp;member);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cursor&nbsp;=&nbsp;scanResult.getStringCursor();<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">while</span>&nbsp;(!<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"0"</span>.equals(cursor));<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment" style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//删除bigkey</span><br>&nbsp;&nbsp;&nbsp;&nbsp;jedis.del(bigSetKey);<br>}<br></code></pre> <h4 style="line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;color: rgb(0, 172, 193);font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">4. SortedSet删除: zscan + zrem</span></h4> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs dart" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;">public&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;delBigZset(<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&nbsp;host,&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;port,&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&nbsp;password,&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&nbsp;bigZsetKey)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;Jedis&nbsp;jedis&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;Jedis(host,&nbsp;port);<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;(password&nbsp;!=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">null</span>&nbsp;&amp;&amp;&nbsp;!<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">""</span>.equals(password))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jedis.auth(password);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;ScanParams&nbsp;scanParams&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;ScanParams().count(<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">100</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&nbsp;cursor&nbsp;=&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"0"</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">do</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ScanResult&lt;Tuple&gt;&nbsp;scanResult&nbsp;=&nbsp;jedis.zscan(bigZsetKey,&nbsp;cursor,&nbsp;scanParams);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">List</span>&lt;Tuple&gt;&nbsp;tupleList&nbsp;=&nbsp;scanResult.getResult();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;(tupleList&nbsp;!=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">null</span>&nbsp;&amp;&amp;&nbsp;!tupleList.isEmpty())&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">for</span>&nbsp;(Tuple&nbsp;tuple&nbsp;:&nbsp;tupleList)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jedis.zrem(bigZsetKey,&nbsp;tuple.getElement());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cursor&nbsp;=&nbsp;scanResult.getStringCursor();<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">while</span>&nbsp;(!<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"0"</span>.equals(cursor));<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment" style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//删除bigkey</span><br>&nbsp;&nbsp;&nbsp;&nbsp;jedis.del(bigZsetKey);<br>}<br></code></pre> </section> <p style="margin-bottom: 10px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-size-adjust: auto;font-size: 15px;word-spacing: 2px;text-align: center;"><span style="font-size: 14px;color: rgb(136, 136, 136);"></span></p> <p style="margin-bottom: 10px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-size-adjust: auto;font-size: 15px;word-spacing: 2px;text-align: center;"><br></p> <blockquote style="padding: 15px 15px 15px 1rem;color: rgb(129, 145, 152);border-left-width: 6px;border-left-color: rgb(220, 230, 240);font-size: 0.9em;line-height: inherit;background: rgb(242, 247, 251);overflow: auto;overflow-wrap: normal;word-break: normal;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-align: start;white-space: normal;"> <p style="font-size: inherit;color: inherit;line-height: inherit;">作者:付磊-起扬<br style="font-size: inherit;color: inherit;line-height: inherit;">https://yq.aliyun.com/articles/531067</p> </blockquote> <p><br></p> <section class="" mpa-from-tpl="t" style="color: rgb(62, 62, 62);font-size: 15px;white-space: normal;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);"> <section class="" mpa-from-tpl="t"> <section mpa-from-tpl="t" style="font-size: medium;display: inline-block;"> <section mpa-from-tpl="t" style="border-left: 1px solid rgb(51, 51, 51);"> <section mpa-from-tpl="t" style="padding-left: 5px;border-left: 5px solid rgb(51, 51, 51);line-height: 1.5em;"> <section class="" powered-by="xiumi.us" mpa-from-tpl="t"> <section mpa-from-tpl="t"> <section mpa-from-tpl="t" style="font-size: 18px;"> <p><span style="font-size: 20px;"></span><span style="font-size: 20px;letter-spacing: 0.544px;">推荐阅读:</span></p> </section> </section> </section> </section> <ul class=" list-paddingleft-2" mpa-from-tpl="t" style=""> <li><p style="margin-top: 5px;"><a href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&amp;mid=2247488507&amp;idx=1&amp;sn=f23c596a76a755a9d3fc942a7d1bfbac&amp;chksm=9f477f33a830f625964606f951001f2b98d5c6c36bd39c156aa4c0298663f9648d73a02eeb0d&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2">我花 10 个小时,写出了小白也能看懂的阿里数据中台分析!</a><br></p></li> <li><p style="margin-top: 5px;"><a href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&amp;mid=2247488280&amp;idx=1&amp;sn=346ffe34602652a6a4b1246cf46b5f9c&amp;chksm=9f477fd0a830f6c6fadd892d05dff980395c68c38ec4fda0915c8cdd44d09b5df1f044ef6ad7&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">万变不离其宗,高并发秒杀系统的设计思考!</a></p></li> <li><p style="margin-top: 5px;"><a href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&amp;mid=2247488262&amp;idx=1&amp;sn=443d945011aeff12e1c71fe13bd7a2b8&amp;chksm=9f477fcea830f6d80e762b9d303169115d18b962cc4b8ced0c6bb8e14bc82eb5a52552ff13fc&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">技术总监的反思录,我是如何失去团队掌控的?</a></p></li> <li><p style="margin-top: 5px;"><a href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&amp;mid=2247488257&amp;idx=1&amp;sn=aab86a0f756da008b4e1462085f82a4b&amp;chksm=9f477fc9a830f6df7b6f0b1a7739b8eba00772323c17b67e904bdf4457af158a70edaf7c3fc4&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">假如有人今天把支付宝的存储服务器炸了,支付宝里的钱是不是就没了。。。</a></p></li> <li><p style="margin-top: 5px;"><a href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&amp;mid=2247488249&amp;idx=1&amp;sn=117c89ec537c187d0f95029916d936ef&amp;chksm=9f477e31a830f727a985be136fd10f275e5943f7ba751b590aa7dc089a7f31abfae546f74dc6&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">再也不用担心被虐啦,高频率JVM面试题,都在这里!</a><br></p></li> <li><p style="margin-top: 5px;"><a href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&amp;mid=2247488152&amp;idx=1&amp;sn=9e519d0a33cb29fb97f48b7245de4fcf&amp;chksm=9f477e50a830f746bc313ea7d856bc9cd0abf8dd52f1ee053f841600ef9e69f0efdba073bf79&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="11" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">饿了么千万级交易系统的重构设计思路</a><br mpa-from-tpl="t"></p></li> <li><p style="margin-top: 5px;"><a href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&amp;mid=2247487067&amp;idx=1&amp;sn=ac98834f2cea7b54e0a050c345cef0d5&amp;chksm=9f476293a830eb854121326198d4507a29371f491979d786e3e528228824c4bc5a4372d3e258&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">支付系统高可用架构设计实战,可用性高达99.999!</a><br mpa-from-tpl="t"></p></li> <li><p style="margin-top: 5px;"><a href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&amp;mid=2247487076&amp;idx=1&amp;sn=ee2728e87a6d9efdc9c5bfd9f12fed0b&amp;chksm=9f4762aca830ebba9aa901e463656f62ab85c0354b3307604440924d1f8ca8ad22d2eee25ea5&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">大型互联网公司分布式ID方案总结</a><br mpa-from-tpl="t"></p></li> </ul> </section> </section> </section> </section> <p style="margin: 15px 8px;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);font-size: 16px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: start;"><br></p> <section class="" mpa-from-tpl="t" style="color: rgb(62, 62, 62);font-size: 15px;white-space: normal;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);"> <section class="" mpa-from-tpl="t"> <p class=""><br mpa-from-tpl="t"></p> <section class="" label="powered by 135editor.com" mpa-from-tpl="t" style="font-family: 微软雅黑;"> <p class="" style="font-size: 18.018px;line-height: 38.4384px;text-align: center;"><span class="" style="font-size: 14px;"><strong mpa-from-tpl="t"><span style="color: rgb(165, 165, 165);">-END-</span></strong><strong class="" mpa-from-tpl="t"></strong><img class="" data-ratio="0.0046875" data-type="jpeg" width="auto" data-w="640" src="/upload/11fcdb7c048b1b63171e2d069a28f95a.jpg" style="color: rgb(0, 112, 192);visibility: visible !important;width: auto !important;"></span></p> <p class="" style="font-size: 18.018px;line-height: 38.4384px;text-align: center;"><span style="font-size: 14px;"><strong mpa-from-tpl="t">架构文摘</strong></span></p> <p class="" style="font-size: 18.018px;line-height: 38.4384px;text-align: center;"><span style="font-size: 14px;">ArchDigest</span></p> <p class="" style="font-size: 18.018px;line-height: 38.4384px;text-align: center;"><span style="font-size: 14px;">架构知识丨大型网站丨大数据丨机器学习</span></p> <p style="font-size: 18.018px;line-height: 38.4384px;text-align: center;"><span class="" style="font-size: 14px;"><img class="" data-cropselx1="0" data-cropselx2="232" data-cropsely1="0" data-cropsely2="233" data-ratio="1" data-s="300,640" data-type="jpeg" data-w="258" src="/upload/a8b6396140939c5102feb0ff0021f94f.jpg" style="visibility: visible !important;width: 233px !important;"></span></p> </section> </section> <pre class="" ng-bind-html="message.MMActualContent" style="font-size: 16px;letter-spacing: 0.544px;white-space: pre-wrap;word-break: normal;"><p style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;text-align: right;line-height: 2em;"><span class="" style="font-size: 14px;">如有收获,点个在看,诚挚感谢</span><img class="" data-ratio="1" data-type="png" data-w="19" width="19px" src="/upload/5f7454d24a334e968c32b8ce9ae53c5.png" style="display: inline-block;vertical-align: text-bottom;visibility: visible !important;width: 19px !important;"></p></pre> </section>

Mybatis 中经典的 9 种设计模式!面试可以吹牛了!

作者:微信小助手

<section powered-by="xiumi.us" style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);" data-mpa-powered-by="yiban.io"> <section> <section powered-by="xiumi.us"> <section> <section powered-by="xiumi.us"> <span style="font-size: 14px;letter-spacing: 0.544px;">往期热门文章:</span> <br> </section> </section> </section> </section> </section> <section powered-by="xiumi.us" style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);"> <h4 style="letter-spacing: 0.544px;color: rgb(62, 62, 62);"> <section style="margin-top: 10px;margin-bottom: 10px;font-size: 15px;font-variant-numeric: normal;font-variant-east-asian: normal;letter-spacing: 0.544px;text-align: left;word-spacing: 1px;widows: 1;caret-color: rgb(255, 0, 0);line-height: 1.75em;"> <span style="font-size: 14px;">1、</span> <a href="http://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&amp;mid=2247489898&amp;idx=1&amp;sn=5c5e41a0f695649046de3db1b1810df5&amp;chksm=e9c5e0dbdeb269cd52f798c675f58295ad0f632283c0fb07db4140949c72796deed7dfe7d434&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2" hasload="1" style="color: rgb(62, 62, 62);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;letter-spacing: 0.544px;font-size: 14px;">《</a> <a href="http://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&amp;mid=2247489402&amp;idx=2&amp;sn=af5c3bb38717e828d92ed48874f03fe8&amp;chksm=e9c5eecbdeb267dd3d05c159bdb9c611f24c4ca7fb7dafa12daf459becb0ef4fab7bcc2d1a67&amp;scene=21#wechat_redirect" target="_blank" data-linktype="2" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;"><span style="font-size: 14px;">往期</span><span style="cursor: pointer;letter-spacing: 0.544px;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);font-size: 14px;">精选优秀博文都在这里了!</span><span style="cursor: pointer;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);color: rgb(62, 62, 62);letter-spacing: 0.544px;">》</span></a> </section> <section style="margin-top: 10px;margin-bottom: 10px;font-size: 15px;font-variant-numeric: normal;font-variant-east-asian: normal;letter-spacing: 0.544px;text-align: left;word-spacing: 1px;widows: 1;caret-color: rgb(255, 0, 0);line-height: 1.75em;"> <span style="font-size: 14px;">2、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&amp;mid=2247490761&amp;idx=1&amp;sn=7a2483e9a0f9870b4fc3c8364d769718&amp;chksm=e9c5e578deb26c6e51a0b9039f5263b736f73b2a4c3bca3921b6f5e78ea5f963625b24f88b96&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2">海量交易订单查询没做“重试”,一哥们“喜提”P3故障!</a></span> </section> <section style="margin-top: 10px;margin-bottom: 10px;font-size: 15px;font-variant-numeric: normal;font-variant-east-asian: normal;letter-spacing: 0.544px;text-align: left;word-spacing: 1px;widows: 1;caret-color: rgb(255, 0, 0);line-height: 1.75em;"> <span style="font-size: 14px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&amp;mid=2247490744&amp;idx=1&amp;sn=0f57a20f486b99503c9d16122ed7a5f3&amp;chksm=e9c5e509deb26c1f53c3841a8b2a092cc487a5e6d8502c9a753eaa6fabcdb102e0d6789e207e&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">3、2020年Java框架排行榜,谁居榜首?</a></span> </section> <section style="margin-top: 10px;margin-bottom: 10px;font-size: 15px;font-variant-numeric: normal;font-variant-east-asian: normal;letter-spacing: 0.544px;text-align: left;word-spacing: 1px;widows: 1;caret-color: rgb(255, 0, 0);line-height: 1.75em;"> <span style="font-size: 14px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&amp;mid=2247490672&amp;idx=1&amp;sn=2fcd199987d644a5a3560fb87b4a3552&amp;chksm=e9c5e5c1deb26cd7a3748c8e8b7a1b193dbbd2a65fa3f232a69c2e0b18b8c5ee1e538dd3be3d&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">4、39 个奇葩代码注释,看完笑哭了。。。</a></span> </section> <section style="margin-top: 10px;margin-bottom: 10px;font-size: 15px;font-variant-numeric: normal;font-variant-east-asian: normal;letter-spacing: 0.544px;text-align: left;word-spacing: 1px;widows: 1;caret-color: rgb(255, 0, 0);line-height: 1.75em;"> <span style="font-size: 14px;">5、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&amp;mid=2247490732&amp;idx=1&amp;sn=c3cc842faeffca602cb89258f9c56a97&amp;chksm=e9c5e51ddeb26c0b8047223784f2057fa2f0bd597d495787f81535990addbaa25c59ed581c7a&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">格式化时间用了YYYY-MM-dd,元旦当天老板喊我回去改Bug!</a></span> </section></h4> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;color: rgb(255, 104, 39);">文章来源:</span> </section> <section> <span style="font-size: 15px;color: rgb(255, 104, 39);">https://juejin.im/post/5d01f0e4f265da1bc23f726a</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">虽然我们都知道有23个设计模式,但是大多停留在概念层面,真实开发中很少遇到。</span> <span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">Mybatis源码中使用了大量的设计模式,阅读源码并观察设计模式在其中的应用,能够更深入的理解设计模式。</span> <br> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">Mybatis至少遇到了以下的设计模式的使用:</span> </section> <section style="text-align: left;margin-top: 15px;margin-bottom: 15px;line-height: 2em;"> <span style="font-size: 15px;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-align: left;">1、</span><span style="color: rgb(255, 104, 39);"><strong><span style="text-align: left;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">Builder模式</span></strong></span><span style="text-align: left;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">,例如SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder;</span></span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">2、<span style="color: rgb(255, 104, 39);"><strong>工厂模式</strong></span>,例如SqlSessionFactory、ObjectFactory、MapperProxyFactory;</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">3、<span style="color: rgb(255, 104, 39);"><strong>单例模式</strong></span>,例如ErrorContext和LogFactory;</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">4、<strong><span style="color: rgb(255, 104, 39);">代理模式</span></strong>,Mybatis实现的核心,比如MapperProxy、ConnectionLogger,用的jdk的动态代理;</span> <span style="font-size: 15px;">还有executor.loader包使用了cglib或者javassist达到延迟加载的效果;</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">5、<span style="color: rgb(255, 104, 39);">组合模式</span>,例如SqlNode和各个子类ChooseSqlNode等;</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">6、<span style="color: rgb(255, 104, 39);"><strong>模板方法模式</strong></span>,例如BaseExecutor和SimpleExecutor,还有BaseTypeHandler和所有的子类例如IntegerTypeHandler;</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">7、<span style="color: rgb(255, 104, 39);"><strong>适配器模式</strong></span>,例如Log的Mybatis接口和它对jdbc、log4j等各种日志框架的适配实现;</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">8、<strong><span style="color: rgb(255, 104, 39);">装饰者模式</span></strong>,例如Cache包中的cache.decorators子包中等各个装饰者的实现;</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">9、<span style="color: rgb(255, 104, 39);"><strong>迭代器模式</strong></span>,例如迭代器模式PropertyTokenizer;</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">接下来挨个模式进行解读,先介绍模式自身的知识,然后解读在Mybatis中怎样应用了该模式。</span> </section> <h1 style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="color: rgb(255, 104, 39);font-size: 15px;"><strong>1、Builder模式</strong></span></h1> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">Builder模式的定义是“将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。</span> <span style="font-size: 15px;">”,它属于创建类模式。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">一般来说,如果一个对象的构建比较复杂,超出了构造函数所能包含的范围,就可以使用工厂模式和Builder模式。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">相对于工厂模式会产出一个完整的产品,Builder应用于更加复杂的对象的构建,甚至只会构建产品的一个部分。</span> </section> <p><img data-ratio="0.7992125984251969" src="/upload/f0a8f51dd9c2e9d0debd97608a355f5.jpg" data-type="jpeg" data-w="508" style="-webkit-tap-highlight-color: transparent;border-style: none;display: block;margin: 10px auto;"></p> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">在Mybatis环境的初始化过程中,SqlSessionFactoryBuilder会调用XMLConfigBuilder读取所有的MybatisMapConfig.xml和所有的*Mapper.xml文件,构建Mybatis运行的核心对象Configuration对象,然后将该Configuration对象作为参数构建一个SqlSessionFactory对象。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">其中XMLConfigBuilder在构建Configuration对象时,也会调用XMLMapperBuilder用于读取*Mapper文件,而XMLMapperBuilder会使用XMLStatementBuilder来读取和build所有的SQL语句。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">在这个过程中,有一个相似的特点,就是这些Builder会读取文件或者配置,然后做大量的XpathParser解析、配置或语法的解析、反射生成对象、存入结果缓存等步骤,这么多的工作都不是一个构造函数所能包括的,因此大量采用了Builder模式来解决。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">对于builder的具体类,方法都大都用build*开头,比如SqlSessionFactoryBuilder为例,它包含以下方法:</span> </section> <p><img data-ratio="0.521875" src="/upload/60c45b03ef458c631dba5f414881a267.jpg" data-type="jpeg" data-w="640" style="-webkit-tap-highlight-color: transparent;border-style: none;display: block;margin: 10px auto;"></p> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">即根据不同的输入参数来构建SqlSessionFactory这个工厂对象。</span> </section> <h1 style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="color: rgb(255, 104, 39);font-size: 15px;"><strong>2、工厂模式</strong></span></h1> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">在Mybatis中比如SqlSessionFactory使用的是工厂模式,该工厂没有那么复杂的逻辑,是一个简单工厂模式。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">简单工厂模式(Simple Factory Pattern):</span> <span style="font-size: 15px;">又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">在简单工厂模式中,可以根据参数的不同返回不同类的实例。</span> <span style="font-size: 15px;">简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。</span> </section> <p><img data-ratio="0.625" src="/upload/99acc1d365265c5d57b98240ce94de50.jpg" data-type="jpeg" data-w="640" style="-webkit-tap-highlight-color: transparent;border-style: none;display: block;margin: 10px auto;"></p> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">SqlSession可以认为是一个Mybatis工作的核心的接口,通过这个接口可以执行执行SQL语句、获取Mappers、管理事务。</span> <span style="font-size: 15px;">类似于连接MySQL的Connection对象。</span> </section> <p><img data-ratio="0.45" src="/upload/cc95dd05c5c93dce7b8124bc7c4c789e.jpg" data-type="jpeg" data-w="640" style="-webkit-tap-highlight-color: transparent;border-style: none;display: block;margin: 10px auto;"></p> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">可以看到,该Factory的openSession方法重载了很多个,分别支持autoCommit、Executor、Transaction等参数的输入,来构建核心的SqlSession对象。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">在DefaultSqlSessionFactory的默认工厂实现里,有一个方法可以看出工厂怎么产出一个产品:</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <img class="rich_pages" data-ratio="0.49107142857142855" data-s="300,640" src="/upload/bf2b739ce09ff0422c22e07d80bf5c7.png" data-type="png" data-w="1792" style=""> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">这是一个openSession调用的底层方法,该方法先从configuration读取对应的环境配置,然后初始化TransactionFactory获得一个Transaction对象</span> <br> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">然后通过Transaction获取一个Executor对象,最后通过configuration、Executor、是否autoCommit三个参数构建了SqlSession。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">在这里其实也可以看到端倪,SqlSession的执行,其实是委托给对应的Executor来进行的。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">而对于LogFactory,它的实现代码:</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <img class="rich_pages" data-ratio="0.45269016697588127" data-s="300,640" src="/upload/217d9cbc7a5de3436d0fa999817d092e.png" data-type="png" data-w="1078" style=""> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">这里有个特别的地方,Log变量的的类型是Constructorextends Log&gt;</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">也就是说该工厂生产的不只是一个产品,而是具有Log公共接口的一系列产品,比如Log4jImpl、Slf4jImpl等很多具体的Log。</span> </section> <h1 style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="color: rgb(255, 104, 39);font-size: 15px;"><strong>3、单例模式</strong></span></h1> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">单例模式(Singleton Pattern):</span> <span style="font-size: 15px;">单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">单例模式的要点有三个:</span> <span style="font-size: 15px;">一是某个类只能有一个实例;</span> <span style="font-size: 15px;">二是它必须自行创建这个实例;</span> <span style="font-size: 15px;">三是它必须自行向整个系统提供这个实例。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">单例模式是一种对象创建型模式,单例模式又名单件模式或单态模式。</span> <br style="-webkit-tap-highlight-color: transparent;"> </section> <p><img data-ratio="0.49636363636363634" src="/upload/7721e92a4d4c4e8f05c959c74fd698d.jpg" data-type="jpeg" data-w="550" style="-webkit-tap-highlight-color: transparent;border-style: none;display: block;margin: 10px auto;"></p> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">在Mybatis中有两个地方用到单例模式,ErrorContext和LogFactory,其中ErrorContext是用在每个线程范围内的单例,用于记录该线程的执行环境错误信息</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">而LogFactory则是提供给整个Mybatis使用的日志工厂,用于获得针对项目配置好的日志对象。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">ErrorContext的单例实现代码:</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <img class="rich_pages" data-ratio="0.48348745046235136" data-s="300,640" src="/upload/dd7e6d5926f1fc994ca6c888ac320308.png" data-type="png" data-w="1514" style=""> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">构造函数是private修饰,具有一个static的局部instance变量和一个获取instance变量的方法,在获取实例的方法中,先判断是否为空如果是的话就先创建,然后返回构造好的对象。</span> <br> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">只是这里有个有趣的地方是,LOCAL的静态实例变量使用了ThreadLocal修饰,也就是说它属于每个线程各自的数据,而在instance()方法中,先获取本线程的该实例,如果没有就创建该线程独有的ErrorContext。</span> </section> <h1 style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="color: rgb(255, 104, 39);font-size: 15px;"><strong>4、代理模式</strong></span></h1> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">代理模式可以认为是Mybatis的核心使用的模式,正是由于这个模式,我们只需要编写Mapper.java接口,不需要实现,由Mybatis后台帮我们完成具体SQL的执行。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">代理模式(Proxy Pattern) :</span> <span style="font-size: 15px;">给某一个对象提供一个代 理,并由代理对象控制对原对象的引用。</span> <span style="font-size: 15px;">代理模式的英 文叫做Proxy或Surrogate,它是一种对象结构型模式。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">代理模式包含如下角色:</span> </section> <ul class="list-paddingleft-2" style=""> <li> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">Subject: 抽象主题角色</span> </section></li> <li> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">Proxy: 代理主题角色</span> </section></li> <li> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">RealSubject: 真实主题角色</span> </section></li> </ul> <p><img data-ratio="0.6640625" src="/upload/e9ce4c8beee4aeaa5aa1c770634708dd.jpg" data-type="jpeg" data-w="640" style="-webkit-tap-highlight-color: transparent;border-style: none;display: block;margin: 10px auto;"></p> <p><img data-ratio="0.5774877650897227" src="/upload/c99d1fb6862d25ec3c67643a04f4b617.jpg" data-type="jpeg" data-w="613" style="-webkit-tap-highlight-color: transparent;border-style: none;display: block;margin: 10px auto;"></p> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">这里有两个步骤,第一个是提前创建一个Proxy,第二个是使用的时候会自动请求Proxy,然后由Proxy来执行具体事务;</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">当我们使用Configuration的getMapper方法时,会调用mapperRegistry.getMapper方法,而该方法又会调用mapperProxyFactory.newInstance(sqlSession)来生成一个具体的代理:</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <img class="rich_pages" data-ratio="0.6550561797752809" data-s="300,640" src="/upload/303c418bb0c177c90bc4e53244f671bc.png" data-type="png" data-w="1780" style=""> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">在这里,先通过T newInstance(SqlSession sqlSession)方法会得到一个MapperProxy对象,然后调用T newInstance(MapperProxymapperProxy)生成代理对象然后返回。</span> <br> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">而查看MapperProxy的代码,可以看到如下内容:</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <img class="rich_pages" data-ratio="0.5687074829931973" data-s="300,640" src="/upload/2c17019de318036c6adbf8b4a80c5c72.png" data-type="png" data-w="1470" style=""> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">非常典型的,该MapperProxy类实现了InvocationHandler接口,并且实现了该接口的invoke方法。</span> <br> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">通过这种方式,我们只需要编写Mapper.java接口类,当真正执行一个Mapper接口的时候,就会转发给MapperProxy.invoke方法</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">而该方法则会调用后续的sqlSession.cud&gt;executor.execute&gt;prepareStatement等一系列方法,完成SQL的执行和返回。</span> </section> <h1 style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="color: rgb(255, 104, 39);font-size: 15px;"><strong>5、组合模式</strong></span></h1> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">组合模式组合多个对象形成树形结构以表示“整体-部分”的结构层次。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">组合模式对单个对象(叶子对象)和组合对象(组合对象)具有一致性,它将对象组织到树结构中,可以用来描述整体与部分的关系。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">同时它也模糊了简单元素(叶子对象)和复杂元素(容器对象)的概念,使得客户能够像处理简单元素一样来处理复杂元素,从而使客户程序能够与复杂元素的内部结构解耦。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">在使用组合模式中需要注意一点也是组合模式最关键的地方:</span> <span style="font-size: 15px;">叶子对象和组合对象实现相同的接口。</span> <span style="font-size: 15px;">这就是组合模式能够将叶子节点和对象节点进行一致处理的原因。</span> </section> <p><img data-ratio="0.7194928684627575" src="/upload/31885f8974d51402e9b328c23b1482c8.jpg" data-type="jpeg" data-w="631" style="-webkit-tap-highlight-color: transparent;border-style: none;display: block;margin: 10px auto;"></p> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">Mybatis支持动态SQL的强大功能,比如下面的这个SQL:</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <img class="rich_pages" data-ratio="0.5799701046337817" data-s="300,640" src="/upload/932b6d68e3f824bf6c9c7fc4d7eb338a.png" data-type="png" data-w="1338" style=""> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">在这里面使用到了trim、if等动态元素,可以根据条件来生成不同情况下的SQL;</span> <br style="-webkit-tap-highlight-color: transparent;"> <span style="font-size: 15px;">在DynamicSqlSource.getBoundSql方法里,调用了rootSqlNode.apply(context)方法,apply方法是所有的动态节点都实现的接口:</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <img class="rich_pages" data-ratio="0.1743119266055046" data-s="300,640" src="/upload/b4388d8fb4d388072d45a10e04089de1.png" data-type="png" data-w="872" style="width: 416px;height: 73px;"> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">对于实现该SqlSource接口的所有节点,就是整个组合模式树的各个节点:</span> </section> <p><img data-ratio="0.8" src="/upload/1dd6ea180b54caa8835b696727654f8.jpg" data-type="jpeg" data-w="640" style="-webkit-tap-highlight-color: transparent;border-style: none;display: block;margin: 10px auto;"></p> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">组合模式的简单之处在于,所有的子节点都是同一类节点,可以递归的向下执行,比如对于TextSqlNode,因为它是最底层的叶子节点,所以直接将对应的内容append到SQL语句中:</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <img class="rich_pages" data-ratio="0.29" data-s="300,640" src="/upload/9bbc9a4b220632e1fe9a2b76be06f417.png" data-type="png" data-w="1200" style=""> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">但是对于IfSqlNode,就需要先做判断,如果判断通过,仍然会调用子元素的SqlNode,即contents.apply方法,实现递归的解析。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <img class="rich_pages" data-ratio="0.3594306049822064" data-s="300,640" src="/upload/43daa488342d230545c28f6c7a04a524.png" data-type="png" data-w="1124" style=""> </section> <h1 style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="color: rgb(255, 104, 39);font-size: 15px;"><strong>6、模板方法模式</strong></span><br></h1> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">模板方法模式是所有模式中最为常见的几个模式之一,是基于继承的代码复用的基本技术。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">模板方法模式需要开发抽象类和具体子类的设计师之间的协作。</span> <span style="font-size: 15px;">一个设计师负责给出一个算法的轮廓和骨架,另一些设计师则负责给出这个算法的各个逻辑步骤。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">代表这些具体逻辑步骤的方法称做基本方法(primitive method);</span> <span style="font-size: 15px;">而将这些基本方法汇总起来的方法叫做模板方法(template method),这个设计模式的名字就是从此而来。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">模板类定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。</span> <span style="font-size: 15px;">使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。</span> </section> <p><img data-ratio="1.1818181818181819" src="/upload/a8f2b3b9c0c956ec1966979a4c0aef60.jpg" data-type="jpeg" data-w="231" style="-webkit-tap-highlight-color: transparent;border-style: none;display: block;margin: 10px auto;"></p> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">在Mybatis中,sqlSession的SQL执行,都是委托给Executor实现的,Executor包含以下结构:</span> </section> <p><img data-ratio="0.5132743362831859" src="/upload/11cdb0919653ff1c6b369ae13bc3e86e.jpg" data-type="jpeg" data-w="452" style="-webkit-tap-highlight-color: transparent;border-style: none;display: block;margin: 10px auto;"></p> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">其中的BaseExecutor就采用了模板方法模式,它实现了大部分的SQL执行逻辑,然后把以下几个方法交给子类定制化完成:</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <img class="rich_pages" data-ratio="0.2571428571428571" data-s="300,640" src="/upload/b74afef5cabd92266b1446079f572cbb.png" data-type="png" data-w="1610" style=""> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">该模板方法类有几个子类的具体实现,使用了不同的策略:</span> </section> <ul class="list-paddingleft-2" style=""> <li> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">简单SimpleExecutor:</span> <span style="font-size: 15px;">每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。</span> <span style="font-size: 15px;">(可以是Statement或PrepareStatement对象)</span> </section></li> <li> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">重用ReuseExecutor:</span> <span style="font-size: 15px;">执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。</span> <span style="font-size: 15px;">(可以是Statement或PrepareStatement对象)</span> </section></li> <li> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">批量BatchExecutor:</span> <span style="font-size: 15px;">执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理的;</span> <span style="font-size: 15px;">BatchExecutor相当于维护了多个桶,每个桶里都装了很多属于自己的SQL,就像苹果蓝里装了很多苹果,番茄蓝里装了很多番茄,最后,再统一倒进仓库。</span> <span style="font-size: 15px;">(可以是Statement或PrepareStatement对象)</span> </section></li> </ul> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">比如在SimpleExecutor中这样实现update方法:</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <img class="rich_pages" data-ratio="0.485273492286115" data-s="300,640" src="/upload/baef802254cf0c9da03e869ac0269e7d.png" data-type="png" data-w="1426" style=""> </section> <h1 style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="color: rgb(255, 104, 39);font-size: 15px;"><strong>7、适配器模式</strong></span><br></h1> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">适配器模式(Adapter Pattern) :</span> <span style="font-size: 15px;">将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。</span> </section> <p><img data-ratio="0.4328125" src="/upload/75cd33d82745b5f2854cc54a4ecabbdb.jpg" data-type="jpeg" data-w="640" style="-webkit-tap-highlight-color: transparent;border-style: none;display: block;margin: 10px auto;"></p> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">在Mybatsi的logging包中,有一个Log接口:</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <img class="rich_pages" data-ratio="1.126843657817109" data-s="300,640" src="/upload/37c541c0b0c06243ab97654bf5c5804c.png" data-type="png" data-w="678" style="width: 305px;height: 344px;"> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">该接口定义了Mybatis直接使用的日志方法,而Log接口具体由谁来实现呢?</span> <br> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">Mybatis提供了多种日志框架的实现,这些实现都匹配这个Log接口所定义的接口方法,最终实现了所有外部日志框架到Mybatis日志包的适配:</span> </section> <p><img data-ratio="0.5828125" src="/upload/484d896ff1d469a7bd213ff4a1800195.jpg" data-type="jpeg" data-w="640" style="-webkit-tap-highlight-color: transparent;border-style: none;display: block;margin: 10px auto;"></p> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">比如对于Log4jImpl的实现来说,该实现持有了org.apache.log4j.Logger的实例,然后所有的日志方法,均委托该实例来实现。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <img class="rich_pages" data-ratio="0.7648809523809523" data-s="300,640" src="/upload/44ae0c4f11b39293b36da091864af58e.png" data-type="png" data-w="1344" style=""> </section> <h1 style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="color: rgb(255, 104, 39);font-size: 15px;"><strong>8、装饰者模式</strong></span><br></h1> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">装饰模式(Decorator Pattern) :</span> <span style="font-size: 15px;">动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">根据翻译的不同,装饰模式也有人称之为“油漆工模式”,它是一种对象结构型模式。</span> </section> <p><img data-ratio="0.8484375" src="/upload/81ea238a98d0b349fe25d40deb0b4be8.jpg" data-type="jpeg" data-w="640" style="-webkit-tap-highlight-color: transparent;border-style: none;display: block;margin: 10px auto;"></p> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">在mybatis中,缓存的功能由根接口Cache(org.apache.ibatis.cache.Cache)定义。</span> <span style="font-size: 15px;">整个体系采用装饰器设计模式,数据存储和缓存的基本功能由PerpetualCache(org.apache.ibatis.cache.impl.PerpetualCache)永久缓存实现,然后通过一系列的装饰器来对PerpetualCache永久缓存进行缓存策略等方便的控制。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">如下图:</span> </section> <p><img data-ratio="0.4984375" src="/upload/d24be1ace74851fc4872274e787145a.jpg" data-type="jpeg" data-w="640" style="-webkit-tap-highlight-color: transparent;border-style: none;display: block;margin: 10px auto;"></p> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">用于装饰PerpetualCache的标准装饰器共有8个(全部在org.apache.ibatis.cache.decorators包中):</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">1、FifoCache:</span> <span style="font-size: 15px;">先进先出算法,缓存回收策略</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">2、LoggingCache:</span> <span style="font-size: 15px;">输出缓存命中的日志信息</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">3、LruCache:</span> <span style="font-size: 15px;">最近最少使用算法,缓存回收策略</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">4、ScheduledCache:</span> <span style="font-size: 15px;">调度缓存,负责定时清空缓存</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">5、SerializedCache:</span> <span style="font-size: 15px;">缓存序列化和反序列化存储</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">6、SoftCache:</span> <span style="font-size: 15px;">基于软引用实现的缓存管理策略</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">7、SynchronizedCache:</span> <span style="font-size: 15px;">同步的缓存装饰器,用于防止多线程并发访问</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">8、WeakCache:</span> <span style="font-size: 15px;">基于弱引用实现的缓存管理策略</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">另外,还有一个特殊的装饰器TransactionalCache:</span> <span style="font-size: 15px;">事务性的缓存</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">正如大多数持久层框架一样,mybatis缓存同样分为一级缓存和二级缓存</span> </section> <ul class="list-paddingleft-2" style=""> <li> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">一级缓存,又叫本地缓存,是PerpetualCache类型的永久缓存,保存在执行器中(BaseExecutor),而执行器又在SqlSession(DefaultSqlSession)中,所以一级缓存的生命周期与SqlSession是相同的。</span> </section></li> </ul> <ul class="list-paddingleft-2" style=""> <li> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">二级缓存,又叫自定义缓存,实现了Cache接口的类都可以作为二级缓存,所以可配置如encache等的第三方缓存。</span> <span style="font-size: 15px;">二级缓存以namespace名称空间为其唯一标识,被保存在Configuration核心配置对象中。</span> </section></li> </ul> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">二级缓存对象的默认类型为PerpetualCache,如果配置的缓存是默认类型,则mybatis会根据配置自动追加一系列装饰器。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">Cache对象之间的引用顺序为:</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">SynchronizedCache–&gt;LoggingCache–&gt;SerializedCache–&gt;ScheduledCache–&gt;LruCache–&gt;PerpetualCache</span> </section> <h1 style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="color: rgb(255, 104, 39);font-size: 15px;"><strong>9、迭代器模式</strong></span></h1> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">迭代器(Iterator)模式,又叫做游标(Cursor)模式。</span> <span style="font-size: 15px;">GOF给出的定义为:</span> <span style="font-size: 15px;">提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。</span> </section> <p><img data-ratio="0.4928571428571429" src="/upload/46928b402b2a1f214ce1f26ce01aea9.jpg" data-type="jpeg" data-w="560" style="-webkit-tap-highlight-color: transparent;border-style: none;display: block;margin: 10px auto;"></p> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">Java的Iterator就是迭代器模式的接口,只要实现了该接口,就相当于应用了迭代器模式:</span> </section> <p><img data-ratio="0.3157894736842105" src="/upload/3a3016f16e2f493fd92af959266159f5.jpg" data-type="jpeg" data-w="646" style="-webkit-tap-highlight-color: transparent;border-style: none;display: block;margin: 10px auto;"></p> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">比如Mybatis的PropertyTokenizer是property包中的重量级类,该类会被reflection包中其他的类频繁的引用到。</span> <span style="font-size: 15px;">这个类实现了Iterator接口,在使用时经常被用到的是Iterator接口中的hasNext这个函数。</span> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <img class="rich_pages" data-ratio="0.8553054662379421" data-s="300,640" src="/upload/e83b6a3cc3e9730a904d964508c06b50.png" data-type="png" data-w="1244" style=""> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <img class="rich_pages" data-ratio="0.4274905422446406" data-s="300,640" src="/upload/66443c44b42b157df0798b2ff4ce6d9a.png" data-type="png" data-w="1586" style=""> </section> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"> <span style="font-size: 15px;">可以看到,这个类传入一个字符串到构造函数,然后提供了iterator方法对解析后的子串进行遍历,是一个很常用的方法类。</span> <br> </section> <section style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);"> <strong><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;color: rgb(255, 76, 65);">往期热门文章:</span></strong> </section> <h4 style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);"> <section style="margin-top: 15px;margin-bottom: 15px;font-variant-numeric: normal;font-variant-east-asian: normal;letter-spacing: 0.544px;color: rgb(62, 62, 62);text-align: left;word-spacing: 1px;widows: 1;caret-color: rgb(255, 0, 0);line-height: 1.75em;"> <span style="font-size: 15px;">1、</span> <a href="http://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&amp;mid=2247489898&amp;idx=1&amp;sn=5c5e41a0f695649046de3db1b1810df5&amp;chksm=e9c5e0dbdeb269cd52f798c675f58295ad0f632283c0fb07db4140949c72796deed7dfe7d434&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2" hasload="1" style="color: rgb(62, 62, 62);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;letter-spacing: 0.544px;font-size: 15px;">《</a> <a href="http://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&amp;mid=2247489402&amp;idx=2&amp;sn=af5c3bb38717e828d92ed48874f03fe8&amp;chksm=e9c5eecbdeb267dd3d05c159bdb9c611f24c4ca7fb7dafa12daf459becb0ef4fab7bcc2d1a67&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;letter-spacing: 0.544px;"><span style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;letter-spacing: 0.544px;font-size: 15px;">历史文章分类导读列表!精选优秀博文都在这里了!</span><span style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;letter-spacing: 0.544px;color: rgb(62, 62, 62);font-size: 15px;">》</span></a> </section> <section style="margin-top: 15px;margin-bottom: 15px;font-variant-numeric: normal;font-variant-east-asian: normal;letter-spacing: 0.544px;color: rgb(62, 62, 62);text-align: left;word-spacing: 1px;widows: 1;caret-color: rgb(255, 0, 0);line-height: 1.75em;"> <span style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;font-size: 15px;">2、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&amp;mid=2247490691&amp;idx=1&amp;sn=51ee2df8d2f46efdbdf628fd2f26b7c7&amp;chksm=e9c5e532deb26c241c036e2b032d4d4eb4974f40e6f1394120bc1faf867220fbcb28a3e4c3cb&amp;scene=21#wechat_redirect" data-itemshowtype="11" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">除了 P 站,程序员在摸鱼时还喜欢上这些网站...</a></span> </section> <section style="margin-top: 15px;margin-bottom: 15px;font-variant-numeric: normal;font-variant-east-asian: normal;letter-spacing: 0.544px;color: rgb(62, 62, 62);text-align: left;word-spacing: 1px;widows: 1;caret-color: rgb(255, 0, 0);line-height: 1.75em;"> 3、 <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&amp;mid=2247490672&amp;idx=1&amp;sn=2fcd199987d644a5a3560fb87b4a3552&amp;chksm=e9c5e5c1deb26cd7a3748c8e8b7a1b193dbbd2a65fa3f232a69c2e0b18b8c5ee1e538dd3be3d&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">39 个奇葩代码注释,看完笑哭了。。。</a> </section> <section style="margin-top: 15px;margin-bottom: 15px;font-variant-numeric: normal;font-variant-east-asian: normal;letter-spacing: 0.544px;color: rgb(62, 62, 62);text-align: left;word-spacing: 1px;widows: 1;caret-color: rgb(255, 0, 0);line-height: 1.75em;"> 4、 <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&amp;mid=2247490606&amp;idx=1&amp;sn=3a2a01ac7125d35d9090cd2e98805232&amp;chksm=e9c5e59fdeb26c89278ff8c3237776960492f24bef54ce4a9f3e657aafe01731b78c6af6de34&amp;scene=21#wechat_redirect" data-itemshowtype="11" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">Stack Overflow上188W+程序员都关注的问题:Java到底是值传递还是引用传递?</a> </section> <section style="margin-top: 15px;margin-bottom: 15px;font-variant-numeric: normal;font-variant-east-asian: normal;letter-spacing: 0.544px;color: rgb(62, 62, 62);text-align: left;word-spacing: 1px;widows: 1;caret-color: rgb(255, 0, 0);line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 0.544px;">5、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&amp;mid=2247490523&amp;idx=1&amp;sn=9f88e0c5703db16bfcfb45c8f50aa1ec&amp;chksm=e9c5e26adeb26b7c1326467a6b51403c2c67c9cc0e13372277238ca630670c3ee65fac43f558&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">Mybatis的这些坑!把我坑惨了!</a></span> </section> <section style="margin-top: 15px;margin-bottom: 15px;font-variant-numeric: normal;font-variant-east-asian: normal;letter-spacing: 0.544px;color: rgb(62, 62, 62);text-align: left;word-spacing: 1px;widows: 1;caret-color: rgb(255, 0, 0);line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 0.544px;">6、</span> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&amp;mid=2247490582&amp;idx=1&amp;sn=267d1ba7698962cd8519671e65ca1cbc&amp;chksm=e9c5e5a7deb26cb11c57ec2920b16bf8e8031fd382f8c1f6b7043aa784fb75abdb03fda0fa85&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;font-size: 15px;letter-spacing: 0.544px;">Dubbo必会的18个面试题!一网打尽!</a> <br> </section> <section style="margin-top: 15px;margin-bottom: 15px;font-variant-numeric: normal;font-variant-east-asian: normal;letter-spacing: 0.544px;color: rgb(62, 62, 62);text-align: left;word-spacing: 1px;widows: 1;caret-color: rgb(255, 0, 0);line-height: 1.75em;"> <span style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;font-size: 15px;">7、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&amp;mid=2247490569&amp;idx=1&amp;sn=d7c8b429de7da6af224bf68c316336f6&amp;chksm=e9c5e5b8deb26caebcee16a74826d81fb8b2183fb0fa1c6ebefcfe80ab3b18fa34dc0fb08aca&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">可以提高千倍效率的Java代码小技巧</a></span> </section> <section style="margin-top: 15px;margin-bottom: 15px;font-variant-numeric: normal;font-variant-east-asian: normal;letter-spacing: 0.544px;color: rgb(62, 62, 62);text-align: left;word-spacing: 1px;widows: 1;caret-color: rgb(255, 0, 0);line-height: 1.75em;"> <span style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;font-size: 15px;">8、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&amp;mid=2247490490&amp;idx=1&amp;sn=0edb2349fccaf6d1de837560440ebed9&amp;chksm=e9c5e20bdeb26b1ddf38eb13fff4c10d06b99d2325de1ff610db4e2e429f9b43ed05f8ff9f5c&amp;scene=21#wechat_redirect" data-itemshowtype="11" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">ThreadLocal面试六连问,你能Hold住吗?</a></span> </section> <section style="margin-top: 15px;margin-bottom: 15px;font-variant-numeric: normal;font-variant-east-asian: normal;letter-spacing: 0.544px;color: rgb(62, 62, 62);text-align: left;word-spacing: 1px;widows: 1;caret-color: rgb(255, 0, 0);line-height: 1.75em;"> <span style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;font-size: 15px;">9、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&amp;mid=2247490555&amp;idx=1&amp;sn=9ff9596ffa6e6712e4c0ffa3b6b71283&amp;chksm=e9c5e24adeb26b5c59cf910a4c848c94d32d76731bb021bb50461c2e3e00481d27a7b5cdf379&amp;scene=21#wechat_redirect" data-itemshowtype="11" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">后端开发甩锅指南!</a></span> </section> <section style="margin-top: 15px;margin-bottom: 15px;font-variant-numeric: normal;font-variant-east-asian: normal;letter-spacing: 0.544px;color: rgb(62, 62, 62);text-align: left;word-spacing: 1px;widows: 1;caret-color: rgb(255, 0, 0);line-height: 1.75em;"> <span style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;font-size: 15px;">10、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&amp;mid=2247490547&amp;idx=1&amp;sn=3449822469746b712d784532473097fe&amp;chksm=e9c5e242deb26b54ea7852145739853c71ee9e43f8e60c1aeba8e3b828cfb43d3d6b0fc66093&amp;scene=21#wechat_redirect" data-itemshowtype="11" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">数据库上云、灾备切换、多云数据同步等问题!教你一键迁移数据!</a></span> </section> <section style="margin-top: 15px;margin-bottom: 15px;font-variant-numeric: normal;font-variant-east-asian: normal;letter-spacing: 0.544px;color: rgb(62, 62, 62);text-align: left;word-spacing: 1px;widows: 1;caret-color: rgb(255, 0, 0);line-height: 1.75em;"> <img data-copyright="0" data-ratio="0.5" data-s="300,640" data-type="png" data-w="800" width="auto" data-backw="574" data-backh="287" data-before-oversubscription-url="/upload/e46fc654dfcccf189c5d81430fa2708f.null" src="/upload/e46fc654dfcccf189c5d81430fa2708f.null" style="font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;color: rgb(51, 51, 51);font-size: 14px;text-align: center;word-spacing: 2px;visibility: visible !important;width: 677px !important;"> </section></h4>

高并发场景下限流,常见的限流算法、方案解析!

作者:微信小助手

<p style="font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-size-adjust: auto;font-size: 15px;word-spacing: 2px;text-align: center;" data-mpa-powered-by="yiban.io"><span style="color: rgb(136, 136, 136);font-size: 14px;">点击蓝色“</span><span style="font-size: 14px;color: rgb(0, 128, 255);">架构文摘</span><span style="color: rgb(136, 136, 136);font-size: 14px;">”关注我哟</span></p> <p style="margin-bottom: 10px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-size-adjust: auto;font-size: 15px;word-spacing: 2px;text-align: center;"><span style="font-size: 14px;color: rgb(136, 136, 136);">加个“</span><span style="color: rgb(0, 128, 255);font-size: 14px;">星标</span><span style="font-size: 14px;color: rgb(136, 136, 136);">”,每天上午 09:25,干货推送!</span></p> <p style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;"><br></p> <p style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;"><br></p> <p style="color: rgba(0, 0, 0, 0.498);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;"><span style="font-size: 14px;">&nbsp; 作者:nick hao</span></p> <p style="color: rgba(0, 0, 0, 0.498);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;"><span style="font-size: 14px;letter-spacing: 0.544px;">&nbsp; 来源:cnblogs.com/haoxinyue/p/6792309.html</span></p> <p style="margin-left: 8px;margin-right: 8px;margin-top: 15px;"><span style="font-size: 15px;">开涛大神在博客中说过:</span><strong><span style="font-size: 15px;">在开发高并发系统时有三把利器用来保护系统:</span></strong><strong><span style="font-size: 15px;">缓存、降级和限流。</span></strong><span style="font-size: 15px;">本文结合作者的一些经验介绍限流的相关概念、算法和常规的实现方式。</span><br></p> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;"><br></span> </section> <h2 style="margin: 10px 8px 15px;"><span style="color: rgb(29, 149, 63);font-size: 20px;">缓存</span><span style="color: rgb(29, 149, 63);font-size: 18px;"></span></h2> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;">缓存比较好理解,在大型高并发系统中,如果没有缓存数据库将分分钟被爆,系统也会瞬间瘫痪。</span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;"><br></span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;">使用缓存不单单能够提升系统访问速度、提高并发访问量,也是保护数据库、保护系统的有效方式。</span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;"><br></span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;">大型网站一般主要是“读”,缓存的使用很容易被想到。</span> <span style="font-size: 15px;">在大型“写”系统中,缓存也常常扮演者非常重要的角色。</span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;"><br></span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;">比如累积一些数据批量写入,内存里面的缓存队列(生产消费),以及HBase写数据的机制等等也都是通过缓存提升系统的吞吐量或者实现系统的保护措施。</span> <span style="font-size: 15px;">甚至消息中间件,你也可以认为是一种分布式的数据缓存。</span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;"><br></span> </section> <h2 style="margin: 10px 8px 15px;"><span style="color: rgb(29, 149, 63);font-size: 20px;">降级</span><span style="color: rgb(29, 149, 63);font-size: 18px;"></span></h2> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;">服务降级是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。</span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;"><br></span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;">降级往往会指定不同的级别,面临不同的异常等级执行不同的处理。</span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;"><br></span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;">根据服务方式:</span> <span style="font-size: 15px;">可以拒接服务,可以延迟服务,也有时候可以随机服务。</span> <span style="font-size: 15px;">根据服务范围:</span> <span style="font-size: 15px;">可以砍掉某个功能,也可以砍掉某些模块。</span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;"><br></span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;">总之服务降级需要根据不同的业务需求采用不同的降级策略。</span> <span style="font-size: 15px;">主要的目的就是服务虽然有损但是总比没有好。</span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;"><br></span> </section> <h2 style="margin: 10px 8px 15px;"><span style="color: rgb(29, 149, 63);font-size: 20px;">限流</span><span style="color: rgb(29, 149, 63);font-size: 18px;"></span></h2> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;">限流可以认为服务降级的一种,限流就是限制系统的输入和输出流量已达到保护系统的目的。</span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;"><br></span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;">一般来说系统的吞吐量是可以被测算的,为了保证系统的稳定运行,一旦达到的需要限制的阈值,就需要限制流量并采取一些措施以完成限制流量的目的。比如:延迟处理,拒绝处理,或者部分拒绝处理等等。</span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;">&nbsp;</span> </section> <h2 style="margin: 10px 8px 15px;"><span style="color: rgb(29, 149, 63);font-size: 20px;">限流的算法</span><span style="color: rgb(29, 149, 63);font-size: 18px;"></span></h2> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;">常见的限流算法有:计数器、漏桶和令牌桶算法。</span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;"><br></span> </section> <p style="margin-left: 8px;margin-right: 8px;margin-bottom: 15px;"><span style="font-size: 18px;color: rgb(29, 149, 63);">计数器</span></p> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;">计数器是最简单粗暴的算法。</span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;"><br></span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;">比如某个服务最多只能每秒钟处理100个请求。我们可以设置一个1秒钟的滑动窗口,窗口中有10个格子,每个格子100毫秒,每100毫秒移动一次,每次移动都需要记录当前服务请求的次数。</span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;"><br></span> </section> <p style="margin-left: 8px;margin-right: 8px;margin-bottom: 15px;"><span style="font-size: 15px;">内存中需要保存10次的次数。可以用数据结构LinkedList来实现。格子每次移动的时候判断一次,当前访问次数和LinkedList中最后一个相差是否超过100,如果超过就需要限流了。</span></p> <section style="box-sizing: border-box;margin: 10px 8px;color: rgb(75, 75, 75);font-family: Verdana, Arial, Helvetica, sans-serif;font-size: 13px;text-align: center;white-space: normal;background-color: rgb(255, 255, 255);"> <img border="0" data-cropselx1="0" data-cropselx2="523" data-cropsely1="0" data-cropsely2="283" data-ratio="0.5411089866156787" src="/upload/978598d2e9af2cc0d98eb247ad4d03dc.png" data-type="png" data-w="523" style="border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box;max-width: 900px;display: inline;margin: 0px;top: 0px;left: 0px;right: 0px;bottom: 0px;width: 523px;height: 283px;" title="image"> </section> <section style="margin-left: 8px;margin-right: 8px;margin-top: 15px;"> <span style="font-size: 15px;">很明显,当滑动窗口的格子划分的越多,那么滑动窗口的滚动就越平滑,限流的统计就会越精确。</span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;"><br></span> </section> <p style="margin-left: 8px;margin-right: 8px;margin-bottom: 15px;"><span style="font-size: 15px;">示例代码如下:</span></p> <pre style="box-sizing: border-box;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code style="box-sizing: border-box;margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 14px;color: rgb(209, 217, 225);line-height: 18px;border-radius: 0px;background: rgb(71, 73, 73);display: block;font-family: Consolas, Inconsolata, Courier, monospace;overflow-x: auto;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;"><span style="box-sizing: border-box;font-size: inherit;color: rgb(150, 152, 150);line-height: inherit;font-style: italic;overflow-wrap: inherit !important;word-break: inherit !important;">//服务访问次数,可以放在Redis中,实现分布式系统的访问计数</span><br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">Long&nbsp;counter&nbsp;=&nbsp;<span style="box-sizing: border-box;font-size: inherit;color: rgb(249, 145, 87);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">0L</span>;<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="box-sizing: border-box;font-size: inherit;color: rgb(150, 152, 150);line-height: inherit;font-style: italic;overflow-wrap: inherit !important;word-break: inherit !important;">//使用LinkedList来记录滑动窗口的10个格子。</span><br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">LinkedList&lt;Long&gt;&nbsp;ll&nbsp;=&nbsp;<span style="box-sizing: border-box;font-size: inherit;color: rgb(204, 153, 204);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;LinkedList&lt;Long&gt;();<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">static</span>&nbsp;<span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;<span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">main(String[]&nbsp;args)</span><br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></span>{<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">&nbsp;&nbsp;Counter&nbsp;counter&nbsp;=&nbsp;<span style="box-sizing: border-box;font-size: inherit;color: rgb(204, 153, 204);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;Counter();<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">&nbsp;&nbsp;counter.doCheck();<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">}<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">private</span>&nbsp;<span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;<span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">doCheck()</span><br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></span>{<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">&nbsp;&nbsp;<span style="box-sizing: border-box;font-size: inherit;color: rgb(204, 153, 204);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">while</span>&nbsp;(<span style="box-sizing: border-box;font-size: inherit;color: rgb(204, 153, 204);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">true</span>)<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">&nbsp;&nbsp;{<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">&nbsp;&nbsp;&nbsp;&nbsp;ll.addLast(counter);<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="box-sizing: border-box;font-size: inherit;color: rgb(204, 153, 204);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;(ll.size()&nbsp;&gt;&nbsp;<span style="box-sizing: border-box;font-size: inherit;color: rgb(249, 145, 87);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">10</span>)<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">&nbsp;&nbsp;&nbsp;&nbsp;{<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ll.removeFirst();<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">&nbsp;&nbsp;&nbsp;&nbsp;}<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="box-sizing: border-box;font-size: inherit;color: rgb(150, 152, 150);line-height: inherit;font-style: italic;overflow-wrap: inherit !important;word-break: inherit !important;">//比较最后一个和第一个,两者相差一秒</span><br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="box-sizing: border-box;font-size: inherit;color: rgb(204, 153, 204);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;((ll.peekLast()&nbsp;-&nbsp;ll.peekFirst())&nbsp;&gt;&nbsp;<span style="box-sizing: border-box;font-size: inherit;color: rgb(249, 145, 87);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">100</span>)<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">&nbsp;&nbsp;&nbsp;&nbsp;{<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="box-sizing: border-box;font-size: inherit;color: rgb(150, 152, 150);line-height: inherit;font-style: italic;overflow-wrap: inherit !important;word-break: inherit !important;">//To&nbsp;limit&nbsp;rate</span><br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">&nbsp;&nbsp;&nbsp;&nbsp;}<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(<span style="box-sizing: border-box;font-size: inherit;color: rgb(249, 145, 87);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">100</span>);<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">&nbsp;&nbsp;}<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">}</code></pre> <p style=""><br></p> <section style="margin: 10px 8px 15px;"> <span style="color: rgb(29, 149, 63);font-size: 18px;">漏桶算法</span> </section> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 15px;">漏桶算法即leaky bucket是一种非常常用的限流算法,可以用来实现流量整形(Traffic Shaping)和流量控制(Traffic Policing)。</span> </section> <section style="margin-left: 8px;mar