作者:微信小助手
<p style="text-align: center;"><img class="" data-copyright="0" data-ratio="0.6144879267277269" data-s="300,640" src="/upload/1b16c374e64a6471ca7e2ba3fe50642f.jpg" data-type="jpeg" data-w="1201" style=""></p> <h2 style="box-sizing: border-box;margin-top: 2rem;margin-bottom: 1rem;color: rgb(21, 153, 87);white-space: normal;"><strong><span style="font-size: 18px;">前言</span></strong></h2> <p style="box-sizing: border-box;font-size: 14px;color: rgb(62, 62, 62);margin-bottom: 15px;margin-top: 15px;line-height: 2em;white-space: normal;"><span style="font-size: 15px;">大家都知道现在很多站点下载资料都是要收费的,无论是积分还是金币,想免费只能说很少很少了,那么这些网站是如何做到资源防盗链的呢?</span></p> <p style="box-sizing: border-box;font-size: 14px;color: rgb(62, 62, 62);margin-bottom: 15px;margin-top: 15px;line-height: 2em;white-space: normal;"><span style="font-size: 15px;">这里推荐一款比较容易上手的神器,Nginx本身提供了secure_link来完成防盗链功能,可以给服务器文件链接添加时间戳和校验码,从而保护服务器文件不被任意下载盗用。</span></p> <h2 style="box-sizing: border-box;margin-top: 2rem;margin-bottom: 1rem;color: rgb(21, 153, 87);white-space: normal;"><span style="font-size: 18px;"><strong>时序图</strong></span></h2> <p style="box-sizing: border-box;font-size: 14px;color: rgb(62, 62, 62);margin-bottom: 15px;margin-top: 15px;line-height: 2em;white-space: normal;"><img class="" data-ratio="0.7264437689969605" src="/upload/7effad1b4d04fab3b178f6eca2dcb98c.png" data-type="png" data-w="658" style="box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;"></p> <p style="box-sizing: border-box;font-size: 14px;color: rgb(62, 62, 62);margin-bottom: 15px;margin-top: 15px;line-height: 2em;white-space: normal;">注:应用服务器后台进行扣除积分逻辑,大家可自行分析CSDN下载地址。</p> <p style="box-sizing: border-box;font-size: 14px;color: rgb(62, 62, 62);margin-bottom: 15px;margin-top: 15px;line-height: 2em;white-space: normal;"><strong style="color: rgb(21, 153, 87);font-size: 16px;">Nginx配置</strong></p> <p style="box-sizing: border-box;font-size: 14px;color: rgb(62, 62, 62);margin-bottom: 15px;margin-top: 15px;line-height: 2em;white-space: normal;"><span style="font-size: 15px;">如何安装Nginx这里不再赘述,安装的时候记得开启ngx<em style="box-sizing: border-box;">http</em>secure<em style="box-sizing: border-box;">link</em>module即可。</span></p> <pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box;overflow: auto;font-family: Consolas, Menlo, Courier, monospace;font-size: 10px;background-color: rgb(29, 31, 33);border-width: 1px;border-style: solid;border-color: rgb(136, 136, 136);padding: 2px;color: rgb(80, 97, 109);line-height: 12px;"> <ol class="linenums list-paddingleft-2" style=""> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">./configure --</span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">with</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">-http_secure_link_module </span><span class="com" style="box-sizing: border-box;">#编译nginx时加入</span></code></p></li> </ol></pre> <p style="box-sizing: border-box;font-size: 14px;color: rgb(62, 62, 62);margin-bottom: 15px;margin-top: 15px;line-height: 2em;white-space: normal;"><span style="font-size: 15px;">安装完成检测:</span></p> <pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box;overflow: auto;font-family: Consolas, Menlo, Courier, monospace;font-size: 10px;background-color: rgb(29, 31, 33);border-width: 1px;border-style: solid;border-color: rgb(136, 136, 136);padding: 2px;color: rgb(80, 97, 109);line-height: 12px;"> <ol class="linenums list-paddingleft-2" style=""> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);">nginx -V</span></code></p></li> </ol></pre> <p style="box-sizing: border-box;font-size: 14px;color: rgb(62, 62, 62);margin-bottom: 15px;margin-top: 15px;line-height: 2em;white-space: normal;"><span style="font-size: 15px;">如果出现以下说明配置成功:</span></p> <pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box;overflow: auto;font-family: Consolas, Menlo, Courier, monospace;font-size: 10px;background-color: rgb(29, 31, 33);border-width: 1px;border-style: solid;border-color: rgb(136, 136, 136);padding: 2px;color: rgb(80, 97, 109);line-height: 12px;"> <ol class="linenums list-paddingleft-2" style=""> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);">configure arguments: --</span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">with</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">-http_secure_link_module --prefix=</span><span class="str" style="box-sizing: border-box;color: rgb(181, 189, 104);">/usr/</span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">local</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">/nginx --</span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">with</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">-http_stub_status_module</span></code></p></li> </ol></pre> <h2 style="box-sizing: border-box;margin-top: 2rem;margin-bottom: 1rem;color: rgb(21, 153, 87);white-space: normal;"><span style="font-size: 18px;"><strong>实例配置</strong></span></h2> <pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box;overflow: auto;font-family: Consolas, Menlo, Courier, monospace;font-size: 10px;background-color: rgb(29, 31, 33);border-width: 1px;border-style: solid;border-color: rgb(136, 136, 136);padding: 2px;color: rgb(80, 97, 109);line-height: 12px;"> <ol class="linenums list-paddingleft-2" style=""> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);">server {</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> listen </span><span class="lit" style="box-sizing: border-box;color: rgb(222, 147, 95);">80</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">;</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> server_name download.</span><span class="lit" style="box-sizing: border-box;color: rgb(222, 147, 95);">52itstyle</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">.com;</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> charset utf-</span><span class="lit" style="box-sizing: border-box;color: rgb(222, 147, 95);">8</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">;</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> location / {</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="com" style="box-sizing: border-box;">#这里配置了2个参数一个是md5,一个是expires</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> secure_link $arg_md5,$arg_expires;</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="com" style="box-sizing: border-box;">#md5的哈希格式为 secret+url+expires,expires为时间戳单位s,url为请求地址</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> secure_link_md5 </span><span class="lit" style="box-sizing: border-box;color: rgb(222, 147, 95);">52itstyle</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);">$uri$arg_e;</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="com" style="box-sizing: border-box;">#这里我们的md5是我们按照secure_link_md5的方式计算的哈希,secure_link会比对它计算的哈希值是否与我们的md5参数一致</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">if</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> ($secure_link = </span><span class="str" style="box-sizing: border-box;color: rgb(181, 189, 104);">""</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">) {</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="com" style="box-sizing: border-box;">#资源不存在或哈希比对失败</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">return</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="lit" style="box-sizing: border-box;color: rgb(222, 147, 95);">402</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">;</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> }</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">if</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> ($secure_link = </span><span class="str" style="box-sizing: border-box;color: rgb(181, 189, 104);">"0"</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">) {</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="com" style="box-sizing: border-box;">#失效超时</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">return</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="lit" style="box-sizing: border-box;color: rgb(222, 147, 95);">405</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">;</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> }</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="com" style="box-sizing: border-box;">#重命名文件名</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> add_header </span><span class="typ" style="box-sizing: border-box;color: rgb(129, 162, 190);">Content</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">-</span><span class="typ" style="box-sizing: border-box;color: rgb(129, 162, 190);">Disposition</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="str" style="box-sizing: border-box;color: rgb(181, 189, 104);">"attachment;filename=$arg_f"</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">;</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">alias</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> /data/site/down.</span><span class="lit" style="box-sizing: border-box;color: rgb(222, 147, 95);">52itstyle</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">.com/;</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> }</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> error_page </span><span class="lit" style="box-sizing: border-box;color: rgb(222, 147, 95);">500</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="lit" style="box-sizing: border-box;color: rgb(222, 147, 95);">502</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="lit" style="box-sizing: border-box;color: rgb(222, 147, 95);">503</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="lit" style="box-sizing: border-box;color: rgb(222, 147, 95);">504</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> /</span><span class="lit" style="box-sizing: border-box;color: rgb(222, 147, 95);">50x</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">.html;</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> error_page </span><span class="lit" style="box-sizing: border-box;color: rgb(222, 147, 95);">402</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="lit" style="box-sizing: border-box;color: rgb(222, 147, 95);">405</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> /</span><span class="lit" style="box-sizing: border-box;color: rgb(222, 147, 95);">40x</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">.html;</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> location = /</span><span class="lit" style="box-sizing: border-box;color: rgb(222, 147, 95);">50x</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">.html {</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> root html;</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> }</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> location = /</span><span class="lit" style="box-sizing: border-box;color: rgb(222, 147, 95);">40x</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">.html {</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> root html;</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> }</span></code></p></li> <li><p><code style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">}</span></code></p></li> </ol></pre> <h3 style="box-sizing: border-box;margin-top: 2rem;margin-bottom: 1rem;color: rgb(21, 153, 87);white-space: normal;"><span style="font-size: 18px;"><strong>参数详解</strong></span></h3> <h4 style="box-sizing: border-box;margin-top: 2rem;margin-bottom: 1rem;color: rgb(21, 153, 87);font-size: 15px;white-space: normal;"><span style="font-size: 15px;">secure_link</span></h4> <p style="box-sizing: border-box;font-size: 14px;color: rgb(62, 62, 62);margin-bottom: 15px;margin-top: 15px;line-height: 2em;white-space: normal;"><span style="font-size: 15px;">语法 : secure_link expression; 默认值: 无 配置段:http, server, location</span></p> <p style="box-sizing: border-box;font-size: 14px;color: rgb(62, 62, 62);margin-bottom: 15px;margin-top: 15px;line-height: 2em;white-space: normal;"><span style="font-size: 15px;">expression由校验值和过期时间组成,其中校验值将会与 secure<em style="box-sizing: border-box;">link</em>md5中的指定参数的MD5哈希值进行对比。</span></p> <p style="box-sizing: border-box;font-size: 14px;color: rgb(62, 62, 62);margin-bottom: 15px;margin-top: 15px;line-height: 2em;white-space: normal;"><span style="font-size: 15px;">如果两个值不一致,$secure<em style="box-sizing: border-box;">link变量的值是空;如果两个值一致,则进行过期检查;如果过期了,则$secure</em>link变量值是0;如果没过期,则为1。</span></p> <p style="box-sizing: border-box;font-size: 14px;color: rgb(62, 62, 62);margin-bottom: 15px;margin-top: 15px;line-height: 2em;white-space: normal;"><span style="font-size: 15px;">如果链接是有时效性的,那么过期时间用时间戳进行设置,在MD5哈希值后面声明,用逗号隔开。如果没有设置过期时间,该链接永久有效。</span></p> <h4 style="box-sizing: border-box;margin-top: 2rem;margin-bottom: 1rem;color: rgb(21, 153, 87);font-size: 15px;white-space: normal;"><span style="font-size: 15px;">secure<em style="box-sizing: border-box;">link</em>md5</span></h4> <p style="box-sizing: border-box;font-size: 14px;color: rgb(62, 62, 62);margin-bottom: 15px;margin-top: 15px;line-height: 2em;white-space: normal;"><span style="font-size: 15px;">语法 : secure<em style="box-sizing: border-box;">link</em>md5 expression; 默认值: 无 配置段:http, server, location</span></p> <p style="box-sizing: border-box;font-size: 14px;color: rgb(62, 62, 62);margin-bottom: 15px;margin-top: 15px;line-height: 2em;white-space: normal;"><span style="font-size: 15px;">expression指定计算md5哈希值的参数,该md5值将会和url中传递的md5值进行对比校验。expression一般包含uri(如demo.com/s/link uri则为/s/link)以及加密 密钥secret,如果该链接具有时效,则expression需包含$secure<em style="box-sizing: border-box;">link</em>expires,expression还可以加入客户端信息,如访问IP,浏览器版本信息等。</span></p> <h2 style="box-sizing: border-box;margin-top: 2rem;margin-bottom: 1rem;color: rgb(21, 153, 87);white-space: normal;"><span style="font-size: 18px;"><strong>Java后端配置</strong></span></h2> <p style="box-sizing: border-box;font-size: 14px;color: rgb(62, 62, 62);margin-bottom: 15px;margin-top: 15px;line-height: 2em;white-space: normal;"><span style="font-size: 15px;">案例,仅供参考:</span></p> <pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box;overflow: auto;font-family: Consolas, Menlo, Courier, monospace;font-size: 10px;background-color: rgb(29, 31, 33);border-width: 1px;border-style: solid;border-color: rgb(136, 136, 136);padding: 2px;color: rgb(80, 97, 109);line-height: 12px;"> <ol class="linenums list-paddingleft-2" style=""> <li><p><code class="java language-java" style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">import</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> org.apache.commons.codec.binary.</span><span class="typ" style="box-sizing: border-box;color: rgb(129, 162, 190);">Base64</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">;</span></code></p></li> <li><p><code class="java language-java" style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">import</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> org.apache.commons.codec.digest.</span><span class="typ" style="box-sizing: border-box;color: rgb(129, 162, 190);">DigestUtils</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">;</span></code></p></li> <li><p><code class="java language-java" style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="com" style="box-sizing: border-box;">/**</span></code></p></li> <li><p><code class="java language-java" style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="com" style="box-sizing: border-box;"> * 生成加密連接</span></code></p></li> <li><p><code class="java language-java" style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="com" style="box-sizing: border-box;"> */</span></code></p></li> <li><p><code class="java language-java" style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">public</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">class</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="typ" style="box-sizing: border-box;color: rgb(129, 162, 190);">SecureLink</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> {</span></code></p></li> <li><p><code class="java language-java" style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">private</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">static</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="typ" style="box-sizing: border-box;color: rgb(129, 162, 190);">String</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> site = </span><span class="str" style="box-sizing: border-box;color: rgb(181, 189, 104);">"https://down.52itstyle.com/"</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">;</span></code></p></li> <li><p><code class="java language-java" style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">private</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">static</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="typ" style="box-sizing: border-box;color: rgb(129, 162, 190);">String</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> secret = </span><span class="str" style="box-sizing: border-box;color: rgb(181, 189, 104);">"52itstyle"</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">;</span></code></p></li> <li><p><code class="java language-java" style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">public</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">static</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="typ" style="box-sizing: border-box;color: rgb(129, 162, 190);">String</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> createLink(</span><span class="typ" style="box-sizing: border-box;color: rgb(129, 162, 190);">String</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> path,</span><span class="typ" style="box-sizing: border-box;color: rgb(129, 162, 190);">String</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> fileName){</span></code></p></li> <li><p><code class="java language-java" style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="typ" style="box-sizing: border-box;color: rgb(129, 162, 190);">String</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> time = </span><span class="typ" style="box-sizing: border-box;color: rgb(129, 162, 190);">String</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">.valueOf((</span><span class="typ" style="box-sizing: border-box;color: rgb(129, 162, 190);">System</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">.currentTimeMillis() / </span><span class="lit" style="box-sizing: border-box;color: rgb(222, 147, 95);">1000</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">) + </span><span class="lit" style="box-sizing: border-box;color: rgb(222, 147, 95);">300</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">); </span><span class="com" style="box-sizing: border-box;">// 5分钟有效</span></code></p></li> <li><p><code class="java language-java" style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="typ" style="box-sizing: border-box;color: rgb(129, 162, 190);">String</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> md5 = </span><span class="typ" style="box-sizing: border-box;color: rgb(129, 162, 190);">Base64</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">.encodeBase64URLSafeString(</span><span class="typ" style="box-sizing: border-box;color: rgb(129, 162, 190);">DigestUtils</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">.md5(secret + path + time));</span></code></p></li> <li><p><code class="java language-java" style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="typ" style="box-sizing: border-box;color: rgb(129, 162, 190);">String</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> url = site + path + </span><span class="str" style="box-sizing: border-box;color: rgb(181, 189, 104);">"?md5="</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> + md5 + </span><span class="str" style="box-sizing: border-box;color: rgb(181, 189, 104);">"&expires="</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> + time + </span><span class="str" style="box-sizing: border-box;color: rgb(181, 189, 104);">"&f="</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">+fileName;</span></code></p></li> <li><p><code class="java language-java" style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">return</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> url;</span></code></p></li> <li><p><code class="java language-java" style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> }</span></code></p></li> <li><p><code class="java language-java" style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">public</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">static</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(178, 148, 187);">void</span><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> main(</span><span class="typ" style="box-sizing: border-box;color: rgb(129, 162, 190);">String</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">[] args) {</span></code></p></li> <li><p><code class="java language-java" style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="com" style="box-sizing: border-box;">//https://down.52itstyle.com/2018101025689452.pdf?md5=FnDYyFzCooI9q8sh1Ffkxg&expires=1539847995&f=分布式秒杀架构.pdf</span></code></p></li> <li><p><code class="java language-java" style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> </span><span class="typ" style="box-sizing: border-box;color: rgb(129, 162, 190);">System</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">.out.println(createLink(</span><span class="str" style="box-sizing: border-box;color: rgb(181, 189, 104);">"2018101025689452.pdf"</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">,</span><span class="str" style="box-sizing: border-box;color: rgb(181, 189, 104);">"分布式秒杀架构.pdf"</span><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">));</span></code></p></li> <li><p><code class="java language-java" style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pln" style="box-sizing: border-box;color: rgb(197, 200, 198);"> }</span></code></p></li> <li><p><code class="java language-java" style="box-sizing: border-box;font-family: monospace, monospace;display: inline;max-width: initial;overflow: initial;line-height: 12px;overflow-wrap: normal;background-color: transparent;border-width: 0px;border-style: initial;border-color: initial;"><span class="pun" style="box-sizing: border-box;color: rgb(197, 200, 198);">}</span></code></p></li> </ol></pre> <h2 style="box-sizing: border-box;margin-top: 2rem;margin-bottom: 1rem;color: rgb(21, 153, 87);white-space: normal;"><span style="font-size: 18px;"><strong>总结</strong></span></h2> <p style="box-sizing: border-box;font-size: 14px;color: rgb(62, 62, 62);margin-bottom: 15px;margin-top: 15px;line-height: 2em;white-space: normal;"><span style="font-size: 15px;">整个加密过程有点对称加密的意思,应用服务根据密钥生成加密地址,Nginx代理服务器进行解密校验,如果通过则允许下载。</span></p> <p style="box-sizing: border-box;font-size: 14px;color: rgb(62, 62, 62);margin-bottom: 15px;margin-top: 15px;line-height: 2em;white-space: normal;"><span style="font-size: 15px;">测试中还发现一个问题,生成的链接有时会报超时失效,可能是由于后端服务器和下载服务器时间不统一导致的,同步更下系统时间即可,</span></p> <p style="box-sizing: border-box;font-size: 14px;color: rgb(62, 62, 62);margin-bottom: 15px;margin-top: 15px;line-height: 2em;white-space: normal;"><span style="font-size: 15px;">如果有做积分下载服务的小伙伴这的确是一个不错的选择,需要注意的是一定要不定期的更换密钥,防止泄露。</span></p> <h2 style="box-sizing: border-box;margin-top: 2rem;margin-bottom: 1rem;color: rgb(21, 153, 87);white-space: normal;"><span style="font-size: 18px;"><strong>参考</strong></span></h2> <p style="box-sizing: border-box;font-size: 14px;color: rgb(62, 62, 62);margin-bottom: 15px;margin-top: 15px;line-height: 2em;white-space: normal;"><span style="font-size: 15px;">http://nginx.org/en/docs/http/ngx<em style="box-sizing: border-box;">http</em>secure<em style="box-sizing: border-box;">link</em>module.html</span></p> <p style="max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-family: 微软雅黑;font-size: 16px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">点击图片查看更多推荐内容</span></strong></p> <p style="max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-family: 微软雅黑;font-size: 16px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">↓↓↓</span></strong></p> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-family: 微软雅黑;font-size: 16px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><a href="http://mp.weixin.qq.com/s?__biz=MzA3OTUyNjkwMw==&mid=2656651026&idx=1&sn=bbed11f9b5328b8ab0d9be01f5ce0a24&chksm=841fc98ab368409c31030825a3c9981707117cfff0dd8272dfc28b66a0504d50f9dd8c397f17&scene=21#wechat_redirect" target="_blank"><span class="" data-positionback="static" style="max-width: 100%;font-size: 0px;display: inline-block;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" data-positionback="static" style="max-width: 100%;top: auto;left: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="js_jump_icon h5_image_link" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="" data-backh="328" data-backw="492" data-before-oversubscription-url="/upload/3f4c131845f3f7ef486c1d09da1267ec.jpg" data-croporisrc="/upload/3f4c131845f3f7ef486c1d09da1267ec.jpg" data-cropx1="0" data-cropx2="1200" data-cropy1="93.38521400778208" data-cropy2="595.3307392996109" data-ratio="0.4191666666666667" data-s="300,640" data-type="jpeg" data-w="1200" src="https://mmbiz.qpic.cn/mmbiz_jpg/CMm9B05ayk8rrcbmekzq9t2zHV6enbiad81nY96nknZrCYic0tA567tpspsPJ48zrTlMias3X9cFpZVapBxIGk96A/640?wx_fmt=jpeg" style="padding: 10px;border-width: 1px;border-style: solid;border-color: rgb(151, 152, 153);border-radius: 0px;box-shadow: rgb(151, 152, 153) 0px 0px 6px;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 514px !important;"></span></span></span></span></span></span></span></span></a></p> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-family: 微软雅黑;font-size: 16px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 13px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(51, 51, 51);font-size: 16px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 13px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">程序员也要养生,给DBA和IT同行的一些建议</span></strong></span></strong></p> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-family: 微软雅黑;font-size: 16px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><a href="http://mp.weixin.qq.com/s?__biz=MzA3OTUyNjkwMw==&mid=2656650976&idx=1&sn=f5dfd429949ed6411b1888f9282db07b&chksm=841fc878b368416e69cfc50ba43e6f5070bac6b7e8df6f868bfab9e227827e45d99311e29c50&scene=21#wechat_redirect" target="_blank"><span class="" data-positionback="static" style="max-width: 100%;font-size: 0px;display: inline-block;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" data-positionback="static" style="max-width: 100%;top: auto;left: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="js_jump_icon h5_image_link" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="" data-croporisrc="/upload/6156bffc738f30914ebb416a7bbf63b1.jpg" data-cropx1="0" data-cropx2="1202" data-cropy1="95.8793774319066" data-cropy2="598.6614785992217" data-ratio="0.41846921797004993" data-s="300,640" data-type="jpeg" data-w="1202" src="https://mmbiz.qpic.cn/mmbiz_jpg/CMm9B05ayk8rrcbmekzq9t2zHV6enbiadZzFI1mFicGFNkppWTjV8ia97fSRv0xd5EcRvqYJe71NSQN2q1V4QXGag/640?wx_fmt=jpeg" style="padding: 10px;border-width: 1px;border-style: solid;border-color: rgb(151, 152, 153);border-radius: 0px;box-shadow: rgb(151, 152, 153) 0px 0px 6px;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 514px !important;"></span></span></span></span></span></span></span></span></a></p> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-family: 微软雅黑;font-size: 16px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 13px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">程序员如何正确的写博客</span></strong></p> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-family: 微软雅黑;font-size: 16px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><a href="http://mp.weixin.qq.com/s?__biz=MzA3OTUyNjkwMw==&mid=2656650967&idx=1&sn=c6a6f356e2fc865c080dcd9f2a3526bd&chksm=841fc84fb3684159d1d7ae98bad1f7be277de0ba89fa3913e089184fc3bed23f905ef6c01f12&scene=21#wechat_redirect" target="_blank" style="color: rgb(87, 107, 149);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" data-positionback="static" style="max-width: 100%;font-size: 0px;display: inline-block;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" data-positionback="static" style="max-width: 100%;top: auto;left: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="js_jump_icon h5_image_link" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="" data-backh="264" data-backw="470" data-before-oversubscription-url="/upload/15675d4160d21e89597f4287675c0d96.jpg" data-croporisrc="/upload/15675d4160d21e89597f4287675c0d96.jpg" data-cropx1="0" data-cropx2="1202" data-cropy1="65.96341463414633" data-cropy2="586.3414634146341" data-ratio="0.43261231281198004" data-s="300,640" data-type="jpeg" data-w="1202" src="https://mmbiz.qpic.cn/mmbiz_jpg/CMm9B05ayk8rrcbmekzq9t2zHV6enbiaduDJHSiaIFJdH52wDALdsLAmouCje0ESFrCUrqmVLVPN73OElJJWCn3Q/640?wx_fmt=jpeg" style="padding: 10px;border-width: 1px;border-style: solid;border-color: rgb(151, 152, 153);border-radius: 0px;box-shadow: rgb(151, 152, 153) 0px 0px 6px;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 492px !important;"></span></span></span></span></span></span></span></span></strong></a></p> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-family: 微软雅黑;font-size: 16px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 13px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">7年Java游戏后端,被淘汰辛酸史</span></strong></p> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-family: 微软雅黑;font-size: 16px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><a href="http://mp.weixin.qq.com/s?__biz=MzA3OTUyNjkwMw==&mid=2656651020&idx=1&sn=f5bd0974e870fe14ab0e0f38acadb1ee&chksm=841fc994b3684082d7c3ae72ff77b253238f18f2797f77a8d7c3207f02617b693f9f2dd25625&scene=21#wechat_redirect" target="_blank"><span class="" data-positionback="static" style="max-width: 100%;font-size: 0px;display: inline-block;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" data-positionback="static" style="max-width: 100%;top: auto;left: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="js_jump_icon h5_image_link" style="max-width: 100%;left: auto;top: auto;right: auto;bottom: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="" data-croporisrc="/upload/bbe10b943a66fbe06ae630971b0985fe.jpg" data-cropx1="0" data-cropx2="1280" data-cropy1="109.26829268292683" data-cropy2="645.2032520325204" data-ratio="0.41953125" data-s="300,640" data-type="jpeg" data-w="1280" src="https://mmbiz.qpic.cn/mmbiz_jpg/CMm9B05ayk8rrcbmekzq9t2zHV6enbiadHiaHoF7mdJj2z3bRXTm1Keuh5vEhuiaz0ia3SYPibgluOgC7lZLO8cTKTQ/640?wx_fmt=jpeg" style="padding: 10px;border-width: 1px;border-style: solid;border-color: rgb(151, 152, 153);border-radius: 0px;box-shadow: rgb(151, 152, 153) 0px 0px 6px;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 492px !important;"></span></span></span></span></span></span></span></span></a></p> <p style="max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);letter-spacing: 0.544px;white-space: normal;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;font-family: 微软雅黑;font-size: 16px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 13px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">记录一次壮烈牺牲的阿里巴巴面试</span></strong></p>
作者:じ☆ve宝贝
## 阿里云镜像服务器功能开通 https://cr.console.aliyun.com/ ### 创建阿里云镜像仓库 公开私有都可以  这一步需要设置代码源,大家可以授权阿里云使用自己的github,具体阿里云配置 我的github大家可以参考 https://github.com/zhangshenglong521/jib.git 创建一个空项目,里面增加一个Dockerfile文件增加FROM gcr.io/distroless/java  github配置完毕后选择刚刚创建的有Dockerfile的项目  点击管理  选择构建直到下方日志提示成功,即可
作者:微信小助手
<blockquote> <p style="letter-spacing: 0.5440000295639038px;white-space: normal;background-color: rgb(255, 255, 255);max-width: 100%;min-height: 1em;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">作者:BigoSprite</span></p> <p style="letter-spacing: 0.5440000295639038px;white-space: normal;background-color: rgb(255, 255, 255);max-width: 100%;min-height: 1em;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="font-size: 14px;">blog.csdn.net/iFuMI/article/details/77920767</span></p> </blockquote> <p><span style="font-size: 15px;"><br></span></p> <p><span style="color: rgb(171, 25, 66);"><strong><span style="font-size: 15px;">执行效果:</span></strong></span><span style="font-size: 15px;"></span></p> <p><span style="font-size: 15px;"><br></span></p> <p><span style="color: rgb(171, 25, 66);"><span style="font-size: 15px;">1. count(1) and count(*)</span></span><span style="font-size: 15px;"></span></p> <p><span style="font-size: 15px;"><br></span></p> <p><span style="font-size: 15px;">当表的数据量大些时,对表作分析之后,使用count(1)还要比使用count(*)用时多了! </span></p> <p><span style="font-size: 15px;">从执行计划来看,count(1)和count(*)的效果是一样的。但是在表做过分析之后,count(1)会比count(*)的用时少些(1w以内数据量),不过差不了多少。 </span></p> <p><span style="font-size: 15px;"><br></span></p> <p><span style="font-size: 15px;">如果count(1)是聚索引,id,那肯定是count(1)快。但是差的很小的。 </span></p> <p><span style="font-size: 15px;">因为count(*),自动会优化指定到那一个字段。所以没必要去count(1),用count(*),sql会帮你完成优化的 因此:</span><span style="font-size: 15px;color: rgb(171, 25, 66);">count(1)和count(*)基本没有差别</span><span style="font-size: 15px;">! </span></p> <p><span style="font-size: 15px;"><br></span></p> <p><span style="font-size: 15px;color: rgb(171, 25, 66);">2. count(1) and count(字段)</span></p> <p><span style="font-size: 15px;"><br></span></p> <p><span style="font-size: 15px;">两者的主要区别是</span></p> <p><span style="font-size: 15px;"><br></span></p> <ol class=" list-paddingleft-2" style="list-style-type: decimal;"> <li><p><span style="font-size: 15px;">count(1) 会统计表中的所有的记录数,</span><span style="font-size: 15px;color: rgb(171, 25, 66);">包含字段为null 的记</span><span style="font-size: 15px;">录。</span></p></li> <li><p><span style="font-size: 15px;">count(字段) 会统计该字段在表中出现的次数,忽略字段为null 的情况。即</span><span style="font-size: 15px;color: rgb(171, 25, 66);">不统计字段为null 的记录</span><span style="font-size: 15px;">。 </span></p></li> </ol> <p><span style="font-size: 12px;"><br></span></p> <p><span style="font-size: 12px;">转自:http://www.cnblogs.com/Dhouse/p/6734837.html</span><span style="font-size: 15px;"></span></p> <p><span style="font-size: 15px;"><br></span></p> <p><span style="color: rgb(171, 25, 66);"><strong><span style="font-size: 15px;">count(*) 和 count(1)和count(列名)区别 </span></strong></span><span style="font-size: 15px;"></span></p> <p><span style="font-size: 15px;"><br></span></p> <p><span style="font-size: 15px;color: rgb(171, 25, 66);">执行效果上:</span><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;"> </span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(171, 25, 66);">count(*)</span><span style="color: rgb(0, 0, 0);font-size: 15px;">包括了所有的列,相当于行数,</span><span style="font-size: 15px;">在统计结果的时候,<strong>不会忽略列值为NULL </strong> </span></p></li> <li><p><span style="font-size: 15px;color: rgb(171, 25, 66);">count(1)</span><span style="font-size: 15px;">包括了忽略所有列,用1代表代码行,在统计结果的时候,<strong>不会忽略列值为NULL</strong> </span></p></li> <li><p><span style="font-size: 15px;color: rgb(171, 25, 66);">count(列名)</span><span style="font-size: 15px;">只包括列名那一列,在统计结果的时候,会忽略列值为空(这里的空不是只空字符串或者0,而是表示null)的计数,<strong>即某个字段值为NULL时,不统计</strong>。</span></p></li> </ul> <p><br></p> <p><span style="font-size: 15px;color: rgb(171, 25, 66);">执行效率上: </span><span style="font-size: 15px;"></span></p> <p><span style="font-size: 15px;"><br></span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;">列名为主键,count(列名)会比count(1)快 </span></p></li> <li><p><span style="font-size: 15px;">列名不为主键,count(1)会比count(列名)快 </span></p></li> <li><p><span style="font-size: 15px;">如果表多个列并且没有主键,则 count(1) 的执行效率优于 count(*) </span></p></li> <li><p><span style="font-size: 15px;">如果有主键,则 select count(主键)的执行效率是最优的 </span></p></li> <li><p><span style="font-size: 15px;">如果表只有一个字段,则 select count(*)最优。</span></p></li> </ul> <p><br></p> <p><span style="font-size: 12px;">转自:</span><span style="font-size: 12px;">http://eeeewwwqq.iteye.com/blog/1972576</span></p> <p><br></p> <p><span style="color: rgb(171, 25, 66);"><strong><span style="font-size: 15px;">实例分析</span></strong></span></p> <p><span style="font-size: 15px;"><br></span></p> <pre style="overflow-x:auto;"><code style="font-size: 0.85em;font-family: Consolas, Menlo, Courier, monospace;margin: 0px 0.15em;white-space: pre;overflow: auto;padding: 0.5em;color: rgb(171, 178, 191);text-size-adjust: none;display: block !important;min-width: 400px;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 44, 52);font-weight: 400;" class="c hljs cpp">mysql> <span class="hljs-function" style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">create table <span class="hljs-title" style="color: rgb(97, 174, 238);font-weight: 400;font-style: normal;">counttest</span><span class="hljs-params" style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">(name <span class="hljs-keyword" style="color: rgb(198, 120, 221);font-weight: 400;font-style: normal;">char</span>(<span class="hljs-number" style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">1</span>)</span>, age <span class="hljs-title" style="color: rgb(97, 174, 238);font-weight: 400;font-style: normal;">char</span><span class="hljs-params" style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">(<span class="hljs-number" style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">2</span>)</span>)</span>;<br>Query OK, <span class="hljs-number" style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">0</span> <span class="hljs-function" style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">rows <span class="hljs-title" style="color: rgb(97, 174, 238);font-weight: 400;font-style: normal;">affected</span> <span class="hljs-params" style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">(<span class="hljs-number" style="color: rgb(209, 154, 102);font-weight: 400;font-style: normal;">0.03</span> sec)</span><br> <br>mysql> insert into counttest values<br> -> <span class="hljs-params" style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">(<span class="hljs-string" style="color: rgb(152, 195, 121);font-weight: 400;font-style: normal;">'a'</span>, <span class="hljs-string" style="color: rgb(152, 195, 121);font-weight: 400;font-style: normal;">'14'</span>)</span>,<span class="hljs-params" style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">(<span class="hljs-string" style="color: rgb(152, 195, 121);font-weight: 400;font-style: normal;">'a'</span>, <span class="hljs-string" style="color: rgb(152, 195, 121);font-weight: 400;font-style: normal;">'15'</span>)</span>, <span class="hljs-params" style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">(<span class="hljs-string" style="color: rgb(152, 195, 121);font-weight: 400;font-style: normal;">'a'</span>, <span class="hljs-string" style="color: rgb(152, 195, 121);font-weight: 400;font-style: normal;">'15'</span>)</span>,<br> -> <span class="hljs-params" style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">(<span class="hljs-string" style="color: rgb(152, 195, 121);font-weight: 400;font-style: normal;">'b'</span>, <span class="hljs-literal" style="color: rgb(86, 182, 194);font-weight: 400;font-style: normal;">NULL</span>)</span>, <span class="hljs-params" style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">(<span class="hljs-string" style="color: rgb(152, 195, 121);font-weight: 400;font-style: normal;">'b'</span>, <span class="hljs-string" style="color: rgb(152, 195, 121);font-weight: 400;font-style: normal;">'16'</span>)</span>,<br> -> <span class="hljs-params" style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">(<span class="hljs-string" style="color: rgb(152, 195, 121);font-weight: 400;font-style: normal;">'c'</span>, <span class="hljs-string" style="color: rgb(152, 195, 121);font-weight: 400;font-style: normal;">'17'</span>)</span>,<br> -> <span class="hljs-params" style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">(<span class="hljs-string" style="color: rgb(152, 195, 121);font-weight: 400;font-style: normal;">'d'</span>, null)</span>,<br> -><span class="hljs-params" style="color: rgb(171, 178, 191);font-weight: 400;font-style: normal;">(<span class="hljs-string" style="color: rgb(152, 195, 121);font-weight: 400;font-style: normal;">'e'</span>, <span class="hljs-string" style="color: rgb(152, 195, 121);font-weight: 400;font-style: normal;">'');<br>Query OK, 8 rows affected (0.01 sec)<br>Records: 8 Duplicates: 0 Warnings: 0<br> <br>mysql> select * from counttest;<br>+------+------+<br>| name | age |<br>+------+------+<br>| a | 14 |<br>| a | 15 |<br>| a | 15 |<br>| b | NULL |<br>| b | 16 |<br>| c | 17 |<br>| d | NULL |<br>| e | |<br>+------+------+<br>8 rows in set (0.00 sec)<br>mysql> select name, count(name), count(1), count(*), count(age), count(distinct(age))<br> -> from counttest<br> -> group by name;<br>+------+-------------+----------+----------+------------+----------------------+<br>| name | count(name) | count(1) | count(*) | count(age) | count(distinct(age)) |<br>+------+-------------+----------+----------+------------+----------------------+<br>| a | 3 | 3 | 3 | 3 | 2 |<br>| b | 2 | 2 | 2 | 1 | 1 |<br>| c | 1 | 1 | 1 | 1 | 1 |<br>| d | 1 | 1 | 1 | 0 | 0 |<br>| e | 1 | 1 | 1 | 1 | 1 |<br>+------+-------------+----------+----------+------------+----------------------+<br>5 rows in set (0.00 sec)</span></span></span></code></pre> <p><span style="font-size: 15px;"><br></span></p> <p><span style="font-size: 12px;">额外参考资料:</span><span style="font-size: 12px;">http://blog.csdn.net/lihuarongaini/article/details/68485838</span></p>
作者:じ☆ve宝贝
<p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">为解决布隆过滤器不能删除元素的问题,布谷鸟过滤器横空出世。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">论文《Cuckoo Filter:Better Than Bloom》作者将布谷鸟过滤器和布隆过滤器进行了深入的对比。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">相比布谷鸟过滤器而言,布隆过滤器有以下不足:</p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="box-sizing: border-box; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em; margin-bottom: 10px;">查询性能弱</p></li> <li><p style="box-sizing: border-box; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em; margin-bottom: 10px;">空间利用效率低</p></li> <li><p style="box-sizing: border-box; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em; margin-bottom: 10px;">不支持反向操作(删除)</p></li> <li><p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">不支持计数。</p></li> </ul> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;"><strong>查询性能弱</strong>是因为布隆过滤器需要使用多个 hash 函数探测位图中多个不同的位点,这些位点在内存上跨度很大,会导致 CPU 缓存行命中率低。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;"><strong>空间效率低</strong>是因为在相同的误判率下,布谷鸟过滤器的空间利用率要明显高于布隆,空间上大概能节省 40% 多。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">不过布隆过滤器并没有要求位图的长度必须是 2 的指数,而布谷鸟过滤器必须有这个要求。从这一点出发,似乎布隆过滤器的空间伸缩性更强一些。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;"><strong>不支持反向删除操作</strong>这个问题着实是击中了布隆过滤器的软肋。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">在一个动态的系统里面元素总是不断的来也是不断的走,布隆过滤器就好比是印迹,来过了就会有痕迹,就算走了也无法清理干净。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">比如你的系统里本来只留下 1kw 个元素,但是整体上来过了上亿的流水元素。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">那布隆过滤器很无奈,它会将这些流失的元素的印迹也会永远存放在那里。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">随着时间的流失,这个过滤器会越来越拥挤,直到有一天你发现它的误判率太高了,不得不进行重建。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">布谷鸟过滤器在论文里声称自己解决了这个问题,它可以有效支持反向删除操作。而且将它作为一个重要的卖点,诱惑你们放弃布隆过滤器改用布谷鸟过滤器。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">但是经过我一段时间的调查研究发现,布谷鸟过滤器并没有它声称的那么美好。它支持的反向删除操作非常鸡肋,以至于你根本没办法使用这个功能。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">在向读者具体说明这个问题之前,还是先给读者仔细讲解一下布谷鸟过滤器的原理。</p> <p style="box-sizing: border-box; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em; margin-bottom: 10px;"><strong style="box-sizing: border-box;color: rgb(233, 105, 0);font-size: inherit;line-height: inherit;">布谷鸟哈希</strong></p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">布谷鸟过滤器源于布谷鸟哈希算法,布谷鸟哈希算法源于生活 —— 那个热爱「鸠占鹊巢」的布谷鸟。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">布谷鸟喜欢滥交(自由),从来不自己筑巢。它将自己的蛋产在别人的巢里,让别人来帮忙孵化。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">待小布谷鸟破壳而出之后,因为布谷鸟的体型相对较大,它又将养母的其它孩子(还是蛋)从巢里挤走 —— 从高空摔下夭折了。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">最简单的布谷鸟哈希结构是一维数组结构,会有两个 hash 算法将新来的元素映射到数组的两个位置。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">如果两个位置中有一个位置为空,那么就可以将元素直接放进去。但是如果这两个位置都满了,它就不得不「鸠占鹊巢」,随机踢走一个,然后自己霸占了这个位置。</p> <pre style="box-sizing: border-box;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;letter-spacing: 2px;text-align: start;word-spacing: 2px;background-color: rgb(255, 255, 255);"><code class="hljs ini" style="box-sizing: border-box;margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 14px;color: rgb(169, 183, 198);line-height: 18px;border-radius: 0px;background: rgb(40, 43, 46);font-family: Consolas, Inconsolata, Courier, monospace;display: block;overflow-x: auto;word-spacing: 0px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;"><span class="hljs-attr" style="box-sizing: border-box;font-size: inherit;color: rgb(165, 218, 45);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">p1</span> = hash1(x) % l<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span class="hljs-attr" style="box-sizing: border-box;font-size: inherit;color: rgb(165, 218, 45);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">p2</span> = hash2(x) % l<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><br></p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">不同于布谷鸟的是,布谷鸟哈希算法会帮这些受害者(被挤走的蛋)寻找其它的窝。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">因为每一个元素都可以放在两个位置,只要任意一个有空位置,就可以塞进去。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">所以这个伤心的被挤走的蛋会看看自己的另一个位置有没有空,如果空了,自己挪过去也就皆大欢喜了。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">但是如果这个位置也被别人占了呢?</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">好,那么它会再来一次「鸠占鹊巢」,将受害者的角色转嫁给别人。然后这个新的受害者还会重复这个过程直到所有的蛋都找到了自己的巢为止。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">正如鲁迅的那句名言「<strong>占自己的巢,让别人滚蛋去吧!</strong>」</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">但是会遇到一个问题,那就是如果数组太拥挤了,连续踢来踢去几百次还没有停下来,这时候会严重影响插入效率。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">这时候布谷鸟哈希会设置一个阈值,当连续占巢行为超出了某个阈值,就认为这个数组已经几乎满了。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">这时候就需要对它进行扩容,重新放置所有元素。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">还会有另一个问题,那就是可能会存在挤兑循环。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">比如两个不同的元素,hash 之后的两个位置正好相同,这时候它们一人一个位置没有问题。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">但是这时候来了第三个元素,它 hash 之后的位置也和它们一样,很明显,这时候会出现挤兑的循环。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">不过让三个不同的元素经过两次 hash 后位置还一样,这样的概率并不是很高,除非你的 hash 算法太挫了。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">布谷鸟哈希算法对待这种挤兑循环的态度就是认为数组太拥挤了,需要扩容(实际上并不是这样)</p> <p style="box-sizing: border-box; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em; margin-bottom: 10px;"><strong style="box-sizing: border-box;color: rgb(233, 105, 0);font-size: inherit;line-height: inherit;">优化</strong></p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">上面的布谷鸟哈希算法的平均空间利用率并不高,大概只有 50%。到了这个百分比,就会很快出现连续挤兑次数超出阈值。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">这样的哈希算法价值并不明显,所以需要对它进行改良。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;"><strong>改良的方案之一</strong>是增加 hash 函数,让每个元素不止有两个巢,而是三个巢、四个巢。这样可以大大降低碰撞的概率,将空间利用率提高到 95%左右。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;"><strong>另一个改良方案</strong>是在数组的每个位置上挂上多个座位。这样即使两个元素被 hash 在了同一个位置,也不必立即「鸠占鹊巢」。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">因为这里有多个座位,你可以随意坐一个。除非这多个座位都被占了,才需要进行挤兑。很明显这也会显著降低挤兑次数。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">这种方案的空间利用率只有 85%左右,但是<strong>查询效率会很高</strong>,同一个位置上的多个座位在内存空间上是连续的,可以有效利用 CPU 高速缓存。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">所以<strong>更加高效的方案</strong>是将上面的两个改良方案融合起来,比如使用 4 个 hash 函数,每个位置上放 2 个座位。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">这样既可以得到时间效率,又可以得到空间效率。这样的组合甚至可以将空间利用率提到高 99%,这是非常了不起的空间效率。</p> <p style="box-sizing: border-box; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em; margin-bottom: 10px;"><strong style="box-sizing: border-box;color: rgb(233, 105, 0);font-size: inherit;line-height: inherit;">布谷鸟过滤器</strong></p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color: rgb(255, 255, 255); line-height: 2em;">布谷鸟过滤器和布谷鸟哈希结构一样,它也是一维数组,但是不同于布谷鸟哈希的是,布谷鸟哈希会存储整个元素,而布谷鸟过滤器中只会存储元素的指纹信息(几个bit,类似于布隆过滤器)。</p> <p style="box-sizing: border-box; margin-bottom: 1.7em; font-size: 15px; color: rgb(62, 62, 62); font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; letter-spacing: 2px; text-align: start; white-space: normal; word-spacing: 2px; background-color
作者:じ☆ve宝贝
Linux使用Java ImageIO裁剪图片是出现此问题: 解决方案: ``` java -version 查看Java版本,如果为openJdk应该删除,并安装Oracle的Java ``` 如果继续有问题: 查看tomcat容器catalina.sh文件中 ``` JAVA_OPTS="-Djava.awt.headless=true -Dawt.toolkit=sun.awt.HToolkit" CATALINA_TMPDIR=/opt/tomcat58080/temp JAVA_OPTS="$JAVA_OPTS -Djava.io.tmpdir=$CATALINA_TMPDIR" ``` 具体原因是Headless模式
作者:じ☆ve宝贝
## windows删除LastUpdated ``` @echo off rem create by studyjava set REPOSITORY_PATH=D:\Develop\Tool\mavenjar rem 正在搜索... for /f "delims=" %%i in (''dir /b /s "%REPOSITORY_PATH%\*lastUpdated*"'') do ( echo %%i del /s /q %%i ) rem 搜索完毕 pause ``` ## Linux删除LastUpdated ``` # create by studyjava # 这里写你的仓库路径 REPOSITORY_PATH=/data/mavenjar echo 正在搜索... find $REPOSITORY_PATH -name "*lastUpdated*" | xargs rm -fr echo 搜索完 ```
作者:微信小助手
<p><img class="currentImg" data-croporisrc="/upload/14fa5721211c31eae9859c87b7d99b89.jpg" data-cropx1="0" data-cropx2="800" data-cropy1="4.316546762589928" data-cropy2="490.64748201438846" data-ratio="0.6075" src="https://mmbiz.qpic.cn/mmbiz_jpg/l89kosVutomcDTGr9DTQeyKrtaaypRpeqIQd8JMHqibIkh1UjNqgQoOV4QHkdagPL7PrcqQcnHpqfyQL8FOiaf9w/640?wx_fmt=jpeg" data-type="jpeg" data-w="800" style="top: 48px;left: 202px;width: 556px;height: 338px;cursor: pointer;" title="点击查看源网页"></p> <p><br></p> <p style="margin: 0px;padding: 0px 10px 0px 9px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-style: normal;font-variant-caps: normal;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;color: rgb(60, 60, 60);font-size: 16px;font-weight: bold;letter-spacing: 1px;text-align: center;line-height: 1.8;background-color: rgb(255, 255, 255);z-index: 10000;"><span style="font-size: 17px;color: rgb(0, 122, 170);">导读</span></p> <p style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;font-style: normal;font-variant-caps: normal;font-weight: normal;letter-spacing: 0.544px;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;"><img class="" data-ratio="0.053125" data-type="png" data-w="640" style="margin-top: 5px !important;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(60, 60, 60);font-weight: bold;letter-spacing: 1px;text-align: center;white-space: normal;background-color: rgb(255, 255, 255);font-size: 15px;display: inline-block;left: 0px;transform: rotateX(60deg);visibility: visible !important;width: 632px !important;height: auto !important;" src="/upload/16c3bc26d4547f0344ee22af769e1434.png"></p> <p><br></p> <p style="line-height: 2em;"><span style="font-size: 15px;">大家也许都有过这样的体验,我们登录一些不是特别常用的软件或网站的时候可以使用QQ、微信或者微博等账号进行授权登陆。例如我们登陆豆瓣网的时候,如果不想单独注册豆瓣网账号的话,就可以选择用微博或者微信账号进行授权登录。这样的场景还有很多,例如登录微博、头条等网站,也都可以选择QQ或者微信登录的方式。</span></p> <p style="text-align: center;"><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="1.02020202020202" data-s="300,640" src="/upload/b11c9b336fbcadf5eb459329d6366e95.png" data-type="png" data-w="594" style="width: 223px;height: 228px;"> <br></p> <p style="text-align: center;"><br></p> <p style="line-height: 2em;"><span style="font-size: 15px;">那么这样的第三方登陆方式到底是怎么实现的呢?难道是腾讯把我们QQ或者微信的账户信息卖给了这些网站不成?很显然,腾讯是不会这么干的,而这种登录方式的实现就是我们这篇文章中要给大家介绍的<strong>OAuth2.0</strong>的认证方式。类似地,在公司内部,如果公司有多套不同的软件系统,例如我们日常使用的GitLab代码管理、公司内网系统、财务报销系统以及很多业务系统的管理后台,是不是也可以实现一个员工账号就能授权访问所有以上这些系统,而不需要每个系统都开通单独的账号,设置独立的密码才行呢?实际上在很多公司都是可以实现这种效果的,这也就是我们通常所说的<strong>SSO单点登录</strong>系统。</span></p> <p style="line-height: 2em;"><br></p> <p style="line-height: 2em;"><span style="font-size: 15px;">在接下来的内容中,码农哥会先给大家具体介绍下OAuth2.0的基本原理,然后再通过Spring Boot实现一套遵循OAuth2.0规范的SSO单点登录系统!</span></p> <p style="line-height: 2em;"><span style="font-size: 16px;"><br></span></p> <p style="margin: 0px;padding: 0px 10px 0px 9px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-style: normal;font-variant-caps: normal;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;color: rgb(60, 60, 60);font-size: 16px;font-weight: bold;letter-spacing: 1px;text-align: center;line-height: 1.8;background-color: rgb(255, 255, 255);z-index: 10000;"><span style="font-size: 17px;color: rgb(0, 122, 170);">什么是OAuth2.0?</span></p> <p style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;font-style: normal;font-variant-caps: normal;font-weight: normal;letter-spacing: 0.544px;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;"><img class="" data-ratio="0.053125" data-type="png" data-w="640" style="margin-top: 5px !important;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(60, 60, 60);font-weight: bold;letter-spacing: 1px;text-align: center;white-space: normal;background-color: rgb(255, 255, 255);font-size: 15px;display: inline-block;left: 0px;transform: rotateX(60deg);visibility: visible !important;width: 632px !important;height: auto !important;" src="/upload/16c3bc26d4547f0344ee22af769e1434.png"></p> <p style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;font-style: normal;font-variant-caps: normal;font-weight: normal;letter-spacing: 0.544px;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;"><br></p> <p style="line-height: 2em;"><span style="font-size: 15px;">OAuth2.0是一种允许第三方应用程序使用资源所有者的<strong>凭据</strong>获得对资源有限访问权限的一种授权协议。例如在前面的例子中,通过微信登录豆瓣网的过程,就相当于微信允许豆瓣网作为第三方应用程序在经过微信用户授权后,通过<strong>微信颁发的授权凭证</strong>有限地访问用户的微信头像、手机号,性别等受限制的资源,从而来构建自身的登录逻辑。</span></p> <p style="line-height: 2em;"><br></p> <p style="line-height: 2em;"><span style="font-size: 15px;">需要说明的是在OAuth2.0协议中第三方应用程序获取的凭证并不等同于资源拥有者持有的用户名和密码,以上面例子来说微信是不会直接将用户的用户名、密码等信息作为凭证返回给豆瓣的。这种<strong>授权访问凭证</strong>一般来说就是一个表示特定范围、生存周期和其访问权限的一个由字符串组成的访问令牌,也就是我们常说的<strong>token</strong>。在这种模式下OAuth2.0协议中通过引入一个<strong>授权层</strong>来将第三方应用程序与资源拥有者进行分离,而这个授权层也就是我们常说的“<strong>auth认证服务</strong>/<strong>sso单点登录服务器</strong>”。</span></p> <p style="line-height: 2em;"><br></p> <p style="line-height: 2em;"><span style="font-size: 15px;"><strong>为了便于理清认证流程中的各个角色,在OAuth2.0协议中定义了以下四个角色:</strong></span></p> <p style="line-height: 2em;"><br></p> <p style="line-height: 2em;"><span style="font-size: 15px;"><strong>1)、resource owner(资源拥有者)</strong></span></p> <p style="line-height: 2em;"><span style="font-size: 15px;">即能够有权授予对保护资源访问权限的实体。例如我们使用通过微信账号登陆豆瓣网,而微信账号信息的实际拥有者就是微信用户,也被称为最终用户。</span></p> <p style="line-height: 2em;"><span style="font-size: 15px;"><br></span></p> <p style="line-height: 2em;"><span style="font-size: 15px;"><strong>2)、resource server(资源服务器)</strong></span></p> <p style="line-height: 2em;"><span style="font-size: 15px;">承载受保护资源的服务器,能够接收使用访问令牌对受保护资源的请求并响应,它与授权服务器可以是同一服务器,也可以是不同服务器。在上述例子中该角色就是微信服务器。</span></p> <p style="line-height: 2em;"><span style="font-size: 15px;"><br></span></p> <p style="line-height: 2em;"><span style="font-size: 15px;"><strong>3)、client(客户端)</strong></span></p> <p style="line-height: 2em;"><span style="font-size: 15px;">代表资源所有者及其授权发出对受保护资源请求的应用程序。在上面的例子中豆瓣网就是这样的角色。</span></p> <p style="line-height: 2em;"><span style="font-size: 15px;"><br></span></p> <p style="line-height: 2em;"><span style="font-size: 15px;"><strong>4)、authorization server(授权服务器)</strong></span></p> <p style="line-height: 2em;"><span style="font-size: 15px;">认证服务器,即服务提供商专门用来处理认证授权的服务器。例如微信开放平台提供的认证服务的服务器。</span></p> <p style="line-height: 2em;"><br></p> <p style="margin: 0px;padding: 0px 10px 0px 9px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-style: normal;font-variant-caps: normal;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;color: rgb(60, 60, 60);font-size: 16px;font-weight: bold;letter-spacing: 1px;text-align: center;line-height: 1.8;background-color: rgb(255, 255, 255);z-index: 10000;"><span style="font-size: 17px;color: rgb(0, 122, 170);">OAuth2.0协议流程</span></p> <p style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;font-style: normal;font-variant-caps: normal;font-weight: normal;letter-spacing: 0.544px;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;"><img class="" data-ratio="0.053125" data-type="png" data-w="640" style="margin-top: 5px !important;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(60, 60, 60);font-weight: bold;letter-spacing: 1px;text-align: center;white-space: normal;background-color: rgb(255, 255, 255);font-size: 15px;display: inline-block;left: 0px;transform: rotateX(60deg);visibility: visible !important;width: 632px !important;height: auto !important;" src="/upload/16c3bc26d4547f0344ee22af769e1434.png"></p> <p style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;font-style: normal;font-variant-caps: normal;font-weight: normal;letter-spacing: 0.544px;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;"><br></p> <p style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;font-style: normal;font-variant-caps: normal;font-weight: normal;letter-spacing: 0.544px;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;line-height: 2em;"><span style="font-size: 15px;">在了解了OAuth2.0协议的基本概念后,接下来让我们一起以程序员的视角(NB点的叫法又叫上帝视角)来分析下OAuth2.0的运行流程。还是以微信授权登陆豆瓣网举例,流程如下:</span></p> <p style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;font-style: normal;font-variant-caps: normal;font-weight: normal;letter-spacing: 0.544px;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;line-height: 2em;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="1.0277777777777777" data-s="300,640" src="/upload/5b2ace865fe17116ae08b7628da4830e.jpg" data-type="jpeg" data-w="936" style=""></p> <p style="line-height: 2em;"><span style="font-size: 15px;"><br></span></p> <p style="line-height: 2em;"><span style="font-size: 15px;">上图通过对微信授权登录豆瓣网过程的分析,已经比较细节的描述了OAuth2.0的运行流程了,大致说明如下:</span></p> <p style="line-height: 2em;"><span style="font-size: 15px;"><br></span></p> <ol style="list-style-type: lower-alpha;" class=" list-paddingleft-2"> <li><p style="line-height: 2em;"><span style="font-size: 15px;">首先微信用户点击豆瓣网微信授权登录按钮后,豆瓣网会将请求通过URL重定向的方式跳转至微信用户授权界面;</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 15px;">此时微信用户实际上是在微信上进行身份认证,与豆瓣网并无交互了,这一点非常类似于我们使用网银支付的场景;</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 15px;">用户使用微信客户端扫描二维码认证或者输入用户名密码后,微信会验证用户身份信息的正确性,如正确,则认为用户确认授权微信登录豆瓣网,此时会先生成一个临时凭证,并携带此凭证通过用户浏览器将请求重定向回豆瓣网在第一次重定向时携带的callBackUrl地址;</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 15px;">之后用户浏览器会携带临时凭证code访问豆瓣网服务,豆瓣网则通过此临时凭证再次调用微信授权接口,获取正式的访问凭据access_token;</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 15px;">在豆瓣网获取到微信授权访问凭据access_token后,此时用户的授权基本上就完成了,后续豆瓣网要做的只是通过此token再访问微信提供的相关接口,获取微信允许授权开发的用户信息,如头像,昵称等,并据此完成自身的用户逻辑及用户登录会话逻辑;</span></p></li> </ol> <p style="line-height: 2em;"><span style="font-size: 15px;"><br></span></p> <p style="line-height: 2em;"><span style="font-size: 15px;">在上述流程中比较关键的动作是用户怎么样才能给Client(豆瓣网)授权,因为只有有了这个授权,Client角色才可以获取访问令牌(access_token),进而通过令牌访问其他资源接口。而关于客户端如何获得授权的问题,在OAuth2.0中定义了四种授权方式,目前微信授权登录使用的是其中一种比较常用的模式authorization_code模式。</span><br></p> <p style="line-height: 2em;"><span style="font-size: 16px;"><br></span></p> <p style="margin: 0px;padding: 0px 10px 0px 9px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-style: normal;font-variant-caps: normal;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;color: rgb(60, 60, 60);font-size: 16px;font-weight: bold;letter-spacing: 1px;text-align: center;line-height: 1.8;background-color: rgb(255, 255, 255);z-index: 10000;"><span style="font-size: 17px;color: rgb(0, 122, 170);">OAuth2.0客户端授权模式</span></p> <p style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;font-style: normal;font-variant-caps: normal;font-weight: normal;letter-spacing: 0.544px;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;"><img class="" data-ratio="0.053125" data-type="png" data-w="640" style="margin-top: 5px !important;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(60, 60, 60);font-weight: bold;letter-spacing: 1px;text-align: center;white-space: normal;background-color: rgb(255, 255, 255);font-size: 15px;display: inline-block;left: 0px;transform: rotateX(60deg);visibility: visible !important;width: 632px !important;height: auto !important;" src="/upload/16c3bc26d4547f0344ee22af769e1434.png"></p> <p style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;font-style: normal;font-variant-caps: normal;font-weight: normal;letter-spacing: 0.544px;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;"><br></p> <p style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;font-style: normal;font-variant-caps: normal;font-weight: normal;letter-spacing: 0.544px;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;line-height: 2em;"><span style="font-size: 15px;">OAuth2.0定义了四种授权模式,它们分别是:</span></p> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;font-style: normal;font-variant-caps: normal;font-weight: normal;letter-spacing: 0.544px;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;line-height: 2em;"><span style="font-size: 15px;">授权码模式(authorization code)<br></span></p></li> <li><p style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;font-style: normal;font-variant-caps: normal;font-weight: normal;letter-spacing: 0.544px;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;line-height: 2em;"><span style="font-size: 15px;">简化模式(implicit)</span></p></li> <li><p style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;font-style: normal;font-variant-caps: normal;font-weight: normal;letter-spacing: 0.544px;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;line-height: 2em;"><span style="font-size: 15px;">密码模式(resource owner password credentials)</span></p></li> <li><p style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;font-style: normal;font-variant-caps: normal;font-weight: normal;letter-spacing: 0.544px;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;line-height: 2em;"><span style="font-size: 15px;">客户端模式(client credentials)</span></p></li> </ul> <p style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;font-style: normal;font-variant-caps: normal;font-weight: normal;letter-spacing: 0.544px;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;line-height: 2em;"><span style="font-size: 15px;">下面我们就分别来分析下这四种客户端授权模式的流程和特点吧!</span></p> <h1 style="margin: 1.5rem 0px 1rem;padding: 0px;font-weight: 400;font-size: 28px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;font-style: normal;font-variant-caps: normal;letter-spacing: 0.5440000295639038px;orphans: auto;text-indent: 0px;text-transform: none;white-space: normal;widows: auto;word-spacing: 0px;-webkit-text-size-adjust: auto;-webkit-text-stroke-width: 0px;text-decoration: none;color: rgb(21, 153, 87);line-height: 1.35;text-align: start;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;"><span style="font-size: 16px;">授权码模式(authorization code)</span></h1> <p><br></p> <p style="line-height: 2em;"><span style="font-size: 15px;">授权码模式(authorization code)是功能最完整、流程最严密的授权模式。它的特点是通过客户端的后台服务器,与“服务提供商”的认证服务进行互动(如微信开放平台),我们前面以微信账号登录豆瓣网的流程就是授权码模式的实现。这种模式下授权代码并不是客户端直接从资源所有者获取,而是通过授权服务器(authorization server)作为中介来获取,授权认证的过程也是资源所有者直接通过授权服务器进行身份认证,避免了资源所有者身份凭证与客户端共享的可能,因此是十分安全的。</span></p> <p style="line-height: 2em;"><span style="font-size: 15px;"><br></span></p> <p style="line-height: 2em;"><span style="font-size: 15px;">例如,微信用户授权登录豆瓣网的过程中,微信授权认证是直接在微信的网站上进行的,即便是输入用户名密码也只有微信授权认证服务器可以获取,因此豆瓣网是感知不到的,从而避免了微信用户账号信息在第三方网站泄露的风险。</span></p> <p style="line-height: 2em;"><span style="font-size: 15px;"><br></span></p> <p style="line-height: 2em;"><span style="font-size: 15px;">由于授权码模式的认证方式与前面微信登录豆瓣网的过程是一致的,因此就不在单独进行流程叙述了!</span></p> <section class="" data-tools="135编辑器" data-id="89204"> <h1 style="margin: 1.5rem 0px 1rem;padding: 0px;font-weight: 400;font-size: 28px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;font-style: normal;font-variant-caps: normal;letter-spacing: 0.5440000295639038px;orphans: auto;text-indent: 0px;text-transform: none;white-space: normal;widows: auto;word-spacing: 0px;-webkit-text-size-adjust: auto;-webkit-text-stroke-width: 0px;text-decoration: none;color: rgb(21, 153, 87);line-height: 1.35;text-align: start;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;"><span style="font-size: 16px;">简化模式(implicit grant type)</span></h1> <p><br></p> <p style="line-height: 2em;"><span style="font-size: 15px;">简化模式是对授权码模式的简化,用于在浏览器中使用脚本语言如JS实现的客户端中,它的特点是不通过客户端应用程序的服务器,而是直接在浏览器中向认证服务器申请令牌,跳过了“授权码临时凭证”这个步骤。其所有的步骤都在浏览器中完成,令牌对访问者是可见的,且客户端不需要认证。如果我们使用此种授权方式来实现微信登录豆瓣网的过程的话,流程如下:</span></p> <p style="line-height: 2em;"><span style="font-size: 15px;"><br></span></p> <p style="line-height: 2em;"><span style="font-size: 15px;"></span></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="1.0277777777777777" data-s="300,640" src="/upload/3467b03f67c81b2f11014ae9fbfb6405.jpg" data-type="jpeg" data-w="936" style=""></p> <p style="text-align: left;"><br></p> <p style="text-align: left;line-height: 2em;"><span style="font-size: 15px;">从上面的流程中可以看到在第4步用户完成授权后,认证服务器是直接返回了access_token令牌至用户浏览器端,而并没有先返回授权码,然后由客户端的后端服务去通过授权码再去获取access_token令牌,从而省去了一个跳转步骤,提高了交互效率。</span></p> <p style="text-align: left;line-height: 2em;"><br></p> <p style="text-align: left;line-height: 2em;"><span style="font-size: 15px;">但是由于这种方式访问令牌access_token会在URL片段中进行传输,因此可能会导致访问令牌被其他未经授权的第三方截取,所以安全性上并不是那么的强壮。</span><br></p> <h1 style="margin: 1.5rem 0px 1rem;padding: 0px;font-weight: 400;font-size: 28px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;font-style: normal;font-variant-caps: normal;letter-spacing: 0.5440000295639038px;orphans: auto;text-indent: 0px;text-transform: none;white-space: normal;widows: auto;word-spacing: 0px;-webkit-text-size-adjust: auto;-webkit-text-stroke-width: 0px;text-decoration: none;color: rgb(21, 153, 87);line-height: 1.35;text-align: start;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;"><span style="font-size: 16px;">密码模式(resource owner password credentials)</span></h1> <p><br></p> <p style="line-height: 2em;"><span style="font-size: 15px;">在密码模式中,用户需要向客户端提供自己的用户名和密码,客户端使用这些信息向“服务提供商”索要授权。这相当于在豆瓣网中使用微信登录,我们需要在豆瓣网输入微信的用户名和密码,然后由豆瓣网使用我们的微信用户名和密码去向微信服务器获取授权信息。</span></p> <p style="line-height: 2em;"><br></p> <p style="line-height: 2em;"><span style="font-size: 15px;">这种模式一般用在用户对客户端高度信任的情况下,因为虽然协议规定客户端不得存储用户密码,但是实际上这一点并不是特别好强制约束。就像在豆瓣网输入了微信的用户名和密码,豆瓣网存储不存储我们并不是很清楚,所以安全性是非常低的。因此一般情况下是不会考虑使用这种模式进行授权的。</span></p> <p style="line-height: 2em;"><br></p> <p style="line-height: 2em;"><span style="font-size: 15px;">假设微信登录豆瓣网的过程使用了此种客户端授权模式,其流程如下:</span></p> <p style="line-height: 2em;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.961038961038961" data-s="300,640" src="/upload/ce7e7d83cb806a185c8b470a28eb3946.jpg" data-type="jpeg" data-w="1001" style=""></p> <p style="text-align: left;"><br></p> <p style="text-align: left;line-height: 2em;"><span style="font-size: 15px;">以上模式逻辑主要在服务器端实现,无法避免客户端应用程序对授权方身份信息的存储,所以一般情况下是不会采用这种授权模式的。</span><br></p> <h1 style="margin: 1.5rem 0px 1rem;padding: 0px;font-weight: 400;font-size: 28px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;font-style: normal;font-variant-caps: normal;letter-spacing: 0.5440000295639038px;orphans: auto;text-indent: 0px;text-transform: none;white-space: normal;widows: auto;word-spacing: 0px;-webkit-text-size-adjust: auto;-webkit-text-stroke-width: 0px;text-decoration: none;color: rgb(21, 153, 87);line-height: 1.35;text-align: start;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;"><span style="font-size: 16px;">客户端模式(client credentials)</span></h1> <p><br></p> <p style="line-height: 2em;"><span style="font-size: 15px;">客户端模式是指客户端以自己的名义,而不是以用户的名义,向“服务提供方”进行认证。严格地说,客户端模式并不属于OAuth2.0协议所要解决的问题。在这种模式下,用户并不需要对客户端授权,用户直接向客户端注册,客户端以自己的名义要求“服务提供商”提供服务。</span></p> <p style="line-height: 2em;"><br></p> <p style="line-height: 2em;"><span style="font-size: 15px;">这种类似于之前共享单车比较火的情况下,出现的全能车的模式,即用户向全能车注册,全能车以自己平台设立的共享账户去开各种品牌的单车。</span><br></p> <br> <p style="margin-top: 10px;margin-bottom: 10px;line-height: 2em;"><span style="font-size: 15px;">综上所述,虽然在OAuth2.0协议中定义了四种客户端授权认证模式,但是实际上大部分实际应用场景中使用的都是授权码(authorization code)的模式,如微信开放平台、微博开放平台等使用的基本都是授权码认证模式。</span><br></p> </section> <p><br></p> <p style="margin: 0px;padding: 0px 10px 0px 9px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-style: normal;font-variant-caps: normal;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;color: rgb(60, 60, 60);font-size: 16px;font-weight: bold;letter-spacing: 1px;text-align: center;line-height: 1.8;background-color: rgb(255, 255, 255);z-index: 10000;"><span style="font-size: 17px;color: rgb(0, 122, 170);">下期预告<br></span></p> <p style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;font-style: normal;font-variant-caps: normal;font-weight: normal;letter-spacing: 0.544px;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;"><img class="" data-ratio="0.053125" data-type="png" data-w="640" style="margin-top: 5px !important;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(60, 60, 60);font-weight: bold;letter-spacing: 1px;text-align: center;white-space: normal;background-color: rgb(255, 255, 255);font-size: 15px;display: inline-block;left: 0px;transform: rotateX(60deg);visibility: visible !important;width: 632px !important;height: auto !important;" src="/upload/16c3bc26d4547f0344ee22af769e1434.png"></p> <p style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;font-style: normal;font-variant-caps: normal;font-weight: normal;letter-spacing: 0.544px;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;"><br></p> <p style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;font-style: normal;font-variant-caps: normal;font-weight: normal;letter-spacing: 0.544px;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;word-spacing: 0px;-moz-text-size-adjust: auto;-webkit-text-stroke-width: 0px;line-height: 2em;"><span style="font-size: 15px;">本篇文章的初衷是想通过总结OAuth2.0的协议流程,来基于Spring Boot集成的spring-security-oauth2包实现一套基于OAuth2.0授权码模式的单点登录系统,以此来解决公司面临的单点登录实际需求,由于篇幅的关系具体SSO单点登录系统的实现过程将在下一篇</span><span style="font-size: 15px;text-decoration: none;">文章中给大家详细介绍,敬请关注!</span></p> <p style="line-height: 2em;"><br></p> <p style="line-height: 2em;"><strong><span style="font-size: 15px;">参考资料:</span></strong></p> <p style="line-height: 2em;"><span style="font-size: 12px;"></span></p> <p style="line-height: 2em;"><span style="font-size: 12px;">http://www.rfcreader.com/#rfc6749</span></p> <p style="line-height: 2em;"><span style="font-size: 12px;">https://www.cnblogs.com/flashsun/p/7424071.html</span></p> <p style="line-height: 2em;"><span style="font-size: 12px;">http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html</span></p> <p style="line-height: 2em;"><span style="font-size: 14px;"><br></span></p> <p style="padding-right: 0em;padding-left: 0em;max-width: 100%;min-height: 1em;white-space: normal;letter-spacing: 2px;text-align: center;background-color: rgb(254, 254, 254);color: rgb(62, 62, 62);font-size: 16px;list-style-type: none;line-height: 25.6px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="__bg_gif" data-ratio="1" data-type="gif" data-w="19" style="box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 19px !important;height: auto !important;" src="/upload/dd153ab34eb13de7d968f500ef94e526.null" width="19px"></p> <p class="" style="padding-right: 0em;padding-left: 0em;max-width: 100%;min-height: 1em;white-space: normal;letter-spacing: 2px;text-align: center;background-color: rgb(254, 254, 254);color: rgb(62, 62, 62);font-size: 16px;list-style-type: none;line-height: 25.6px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-align: center;background-color: rgb(254, 254, 254);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;letter-spacing: 0.544px;color: rgb(137, 135, 145);font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">—————END—————</span></p> <p class="" style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-align: center;background-color: rgb(254, 254, 254);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;text-indent: 0em;white-space: normal;text-align: center;background-color: rgb(254, 254, 254);word-spacing: 2px;font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;line-height: 25.6px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="" data-copyright="0" data-ratio="1" data-s="300,640" data-type="jpeg" data-w="258" 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;text-indent: 0em;border-radius: 4px;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 258px !important;height: auto !important;" src="/upload/b5b5c2f05535c1a82d6645d73092e98f.jpg"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin-top: 15px;max-width: 100%;min-height: 1em;font-variant-numeric: normal;font-variant-east-asian: normal;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;font-size: 16px;line-height: 1.75em;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(127, 127, 127);line-height: 1.75em;">识别图片二维码,关注“</span><span style="max-width: 100%;line-height: 1.75em;color: rgb(0, 176, 240);">无敌码农</span><span style="max-width: 100%;color: rgb(127, 127, 127);line-height: 1.75em;">”获取精彩内容</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;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;box-sizing: border-box !important;word-wrap: break-word !important;">(点击</span><span style="max-width: 100%;line-height: 22.4px;color: rgb(0, 128, 255);box-sizing: border-box !important;word-wrap: break-word !important;">上方公众号</span><span style="max-width: 100%;color: rgb(255, 41, 65);line-height: 22.4px;box-sizing: border-box !important;word-wrap: break-word !important;">,可快速关注)</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;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;word-wrap: break-word !important;">来源:野兽 ,</span></p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;word-wrap: break-word !important;">www.cnblogs.com/ys-ys/p/9546160.html</span></p> </blockquote> <p><br></p> <p>git的定义是一个内容寻址文件系统。内容、寻址、文件、系统,该来的总会来的…</p> <p><br></p> <p>本文旨在通过实践来介绍.git文件夹中的目录及文件功能,属git基础知识。但在此基础上可解决各git使用过程中可能遇到的问题,如“.git文件夹占用空间大”,“git如何找回丢失的对象(提交)”,”git diff 对比依据是什么”等,</p> <p><br></p> <p>话不多说,撸起袖子就是干,来看看 .git 是个啥样,这些个货色都是干嘛的。</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 初始化git,查看内容</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git init 产生一个.git隐藏文件夹</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">cd .git</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">ls -F1</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 初始化时的.git长这样</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># HEAD</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># config</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># description</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># hooks/</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># info/</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># objects/</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># refs/</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 日常工作中的.git大概长这样</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># COMMIT_EDITMSG</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># config</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># description</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># hooks/</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># index</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># info/</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># logs/</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># objects/</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># refs/</span></p> </blockquote> <p><br></p> <p>随着之后的多种 git操作 ,还会存在如 MERGE_HEAD 、 MERGE_MODE等和 COMMIT_EDITMSG 类似功能的文件,branches(分支信息)、lost-found(存储被悬挂起/丢失的提交对象)、packed-refs(压缩后的refs记录)等和logs、objects类似功能的文件夹。</p> <p><br></p> <p>以上面的.git为例做个简单的介绍:</p> <p><br></p> <p>COMMIT_EDITMSG 最近一次的 commit edit message ;</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 编写提交信息的两种姿势</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git commit</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 自动打开文件编辑,在文件中输入信息即可</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git commit -m msg</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 信息都会被保存到 COMMIT_EDITMSG</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 如需修改提交信息,不可直接编辑COMMIT_EDITMSG,可执行以下命令</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git commit --amend </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 自动打开文件编辑,在文件中修改信息即可</span></p> </blockquote> <p><br></p> <p>description 描述文件,打开后里面提醒该为git仓库创建个描述(Unnamed repository; edit this file ‘description’ to name the repository.)。</p> <p><br></p> <p>config 文件包含项目特有的配置选项,如一些常用项:</p> <p><br></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p>[core] ignorecase 是否忽略文件大小写;</p></li> <li><p>[remote "origin"] url 配置远程仓库地址;</p></li> <li><p>[remote "origin"] fetch 远程分支映射关系;</p></li> <li><p>[user] name 用户名</p></li> <li><p>[user] email 邮箱</p></li> <li><p>[alias] 命令别名配置 : cmt = commit</p></li> </ul> <p><br></p> <p>抑或更多其他config参数…</p> <p><br></p> <p>全局配置文件在 ~/.gitconfig ,Windows应该是在Users/Administrator/.gitconfig。</p> <p><br></p> <p>info/ 文件夹用以存储一些有关git仓库的信息,如exclude</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 包含一个全局性排除(global exclude)文件,用以放置那些不希望被记录在 .gitignore 文件中的忽略模式(ignored patterns);</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">echo for git ignore > git-ignore</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">echo for git exclude > git-exclude</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">echo git-ignore > .gitignore</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git status</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># On branch test</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># Untracked files:</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># (use "git add <file>..." to include in what will be committed)</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># .gitignore</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># git-exclude</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># git-ignore已被忽略,还有2个untracked的文件</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">cd .git</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">cd info/</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">vi exclude</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 最后一行新增 git-exclude</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">cd ../..</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git status</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># On branch test</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># Untracked files:</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># (use "git add <file>..." to include in what will be committed)</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># .gitignore</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># git-exclude 已被忽略,只有.gitignore还是untracked</span></p> </blockquote> <p><br></p> <p>除exclude文件外,还可能会有refs、grafts,attributes等文件</p> <p><br></p> <p>hooks/ 文件夹包含客户端或服务端的钩子脚本(hook scripts),如pre-commit,post-receive等:</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">vi .git/hooks/pre-commit</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 保存以下信息 第一行指定用什么执行</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">#!/bin/sh</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">echo "Message for pre commit";</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">exit 1;</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 开执行权限</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">chmod +x .git/hooks/pre-commit # user+group+other 执行x(1)权限 ,备注 r(4,read),w(2,write),x(1,execute),-(0,no permission),s(special)</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">touch commit-hook-test</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git add .</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git commit -m “pre-commit test“</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 你会看到以下信息</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># Message for pre commit</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 如果不exit,则继续执行,详情可参考.git/hooks/下的*.sample文件</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># Message for pre commit</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># [test 038e6ec] pre-commit test</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 1 file changed, 1 insertion(+), 1 deletion(-)</span></p> </blockquote> <p><br></p> <p>logs/ 放置git仓库操作记录的文件夹,包含HEAD文件 和 refs文件夹。</p> <p><br></p> <p>HAED 文件包含对 git分支 的操作记录,如</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">vi HEAD</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 99a10c283c33beed7f31c210a6c8b411d2a31085 5daf6094ea2cc60d17e947c0435096a4bdafe82d yeshou <yeshou@xxx.com> 1535082919 +0800 commit: rm files</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 5daf6094ea2cc60d17e947c0435096a4bdafe82d b8e02a5f9c2bf44342d15f5ea1e60ffd9434765a yeshou <yeshou@xxx.com> 1535087285 +0800 checkout: moving from test to master</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 先是删除文件后提交了次,再是由test检出到master</span></p> </blockquote> <p><br></p> <p>refs 文件夹包含 heads 文件夹,remote文件夹。heads 记录本地相关的各 git分支 操作记录,remote 记录远程仓库相关的各 git分支 操作记录</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">cd heads</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">ls</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># master master分支操作记录</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># test test分支操作记录</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">cd remote/origin</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">ls</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># master 远程master分支操作记录</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># test 远程test分支操作记录</span></p> </blockquote> <p><br></p> <p>HEAD 文件指示当前被检出(所在)的分支,如当前在test分支,文件内容则为ref: refs/heads/test。</p> <p><br></p> <p>index 文件是当前版本的文件索引,包含生成当前树(唯一确定的)对象的所虚信息,可用于快速比对工作树和其他提交树对象的差异(各commit和HEAD之间的diff),可用于存储单文件的多个版本以有效的解决合并冲突。可使用git ls-files 查看index文件内容。如:</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git commit 的一次提交从index中的信息生成tree对象,将其存储在对象数据库中,并与本次新的commit做关联,产生本次commit的tree信息(下面的objects介绍中会提到commit和tree)。</span></p> </blockquote> <p><br></p> <p>refs/ (references) 文件夹存储指向数据(分支)的提交对象指针;其中 heads 文件夹记录内部文件对应名称的分支的提交对象;tags记录内部文件对应名称的标签的提交对象;remotes记录内部文件对应名称的远程仓库分支的提交对象;</p> <p><br></p> <p>举个例子:</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">cat .git/refs/heads/master</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> # ce1fed3fdbaf12e816e3028055f9feee57b33b45 当前master的提交记录</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> git checkout -b test # 检出一个新分支</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> find .git</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> # 多了个 .git/refs/heads/test 文件</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> git log</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> # commit 63a85dcbc6978f2d43996f5bebc38993c2afadaa (HEAD -> test)</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> # Author: yeshou <yeshou@xxx.com></span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> # Date: Sat Aug 25 13:57:26 2018 +0800</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> #</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> # branch test : edit test : add line : write d</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> # commit ce1fed3fdbaf12e816e3028055f9feee57b33b45 (master)</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> # Author: yeshou <yeshou@xxx.com></span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> # Date: Sat Aug 25 12:40:35 2018 +0800</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> # </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> # edit test : add line : write c</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> cat .git/refs/heads/test</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> # 63a85dcbc6978f2d43996f5bebc38993c2afadaa 当前test的最近提交记录</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> cat .git/refs/heads/master</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> # ce1fed3fdbaf12e816e3028055f9feee57b33b45 依然是当前master的最近提交记录</span></p> </blockquote> <p><br></p> <p>另两者亦然。</p> <p><br></p> <p>objects/ 文件夹用以存储git仓库中的所有数据内容。</p> <p><br></p> <p>一步步来…</p> <p><br></p> <p>先看看这个文件夹里是怎么存数据内容的,再理解这些数据内容又是什么。</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 为了清晰的看明白objects文件夹中文件的生成,初始化.git</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">rm -rf .git</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git init </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">cd .git </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">find .git # 这时候objects文件夹下只有pack和info 两个空文件夹</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">touch test</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">vi test</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 输入 a ,保存,退出</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git add test</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">find .git</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># objects 下多了个文件夹,且里面有文件</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># .git/objects/44</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># .git/objects/44/2406aa9341668f9c43c2d5378a777ad69324a0</span></p> </blockquote> <p><br></p> <p>验证下这个文件内容是什么,注意,这是个二进制球,呸…是文件,文明观球,呸…是观看。这里我们用传说中git中的手术刀( git cat-file )来解剖git文件。</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git cat-file -p 442406aa9341668f9c43c2d5378a777ad69324a0</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 输出 a</span></p> </blockquote> <p><br></p> <p>9de29bb2d1d6434b8b29ae775ad8c2e48c5391 是个二进制文件,是git对象中的blob对象,它记录了当前版本的该文件的数据内容,并以SHA-1计算产生一个40个字符的校验和。 根据官方描述:这是一个 SHA-1 哈希值——一个将待存储的数据外加一个头部信息(header)一起做 SHA-1 校验运算而得的校验和。</p> <p><br></p> <p>继续操作,修改test</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">vi test</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 第二行输入 b ,保存,退出</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git add test</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">find .git</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># objects 下又多了个文件夹,且里面也有文件</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># .git/objects/bf</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># .git/objects/bf/daa0f1c3415c09d3080063911d155fd7259d18</span></p> </blockquote> <p><br></p> <p>这次的二进制文件的数据内容是 a (手动换行) b 。</p> <p><br></p> <p>继续走下去:</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git commit -m “add test”</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># wtf,怎么突然生出2个文件夹,来来来,看看内容</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># .git/objects/3e</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># .git/objects/3e/5f95cd5c4f0ff429522b0fdfeda9369f92d89c</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># .git/objects/fd</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># .git/objects/fd/1332e4e95f8a64682c1516e175abb66b6f6325</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git cat-file -t fd1332e4e95f8a64682c1516e175abb66b6f6325</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># commit</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git cat-file -p fd1332e4e95f8a64682c1516e175abb66b6f6325</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># tree对象、作者、提交者、提交日期、提交信息、父对象(有的话带一个或多个父对象)</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># tree 3e5f95cd5c4f0ff429522b0fdfeda9369f92d89c </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># author yeshou <yeshou@xxx.com> 1535168447 +0800</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># committer yeshou <yeshou@xxx.com> 1535168447 +0800</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># add dir-test </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git cat-file -t 3e5f95cd5c4f0ff429522b0fdfeda9369f92d89c</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># tree</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git cat-file -p 3e5f95cd5c4f0ff429522b0fdfeda9369f92d89c</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 100644 blob bfdaa0f1c3415c09d3080063911d155fd7259d18 test</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git cat-file -p bfdaa0f1c3415c09d3080063911d155fd7259d18</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># a (换行) b</span></p> </blockquote> <p><br></p> <p>3e5f95cd5c4f0ff429522b0fdfeda9369f92d89c 也是个二进制文件,是git对象中的tree对象,记录着blob标识符、路径名和在一个tree下的所有文件的元数据。</p> <p><br></p> <p>fd1332e4e95f8a64682c1516e175abb66b6f6325 又是个二进制文件,是git对象中的commit对象,它记录了当前版本的一次提交数据内容,包含tree对象、作者、提交者、提交日期、提交信息、父对象(有的话带一个或多个父对象)。</p> <p><br></p> <p>然后,pack文件夹是干嘛的?</p> <p><br></p> <p>随着objects文件夹下的文件夹和文件不断生成(也就是N多次的commit之后),objects文件夹明显会”长大”,这时开发者可以用 git gc 来对之前的操作的对象做整理压缩。</p> <p>pack 文件夹内有2个文件 pack-(SHA-1).pack 和 pack-(SHA-1).idx 前者是以压缩形式存储之前记录对象的文件,后者用以存储访问索引的文件。</p> <p><br></p> <p>举个例子:</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git gc </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># Counting objects: 12, done.</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># Delta compression using up to 4 threads.</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># Compressing objects: 100% (4/4), done.</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># Writing objects: 100% (12/12), done.</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># Total 12 (delta 0), reused 0 (delta 0)</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">find .git</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 发现少了很多objects里的文件夹和文件,多了以下2个文件</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># .git/objects/pack/pack-2021ec3cb18c796fdfca8ef616fb6a20b1449ab1.pack</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># .git/objects/pack/pack-2021ec3cb18c796fdfca8ef616fb6a20b1449ab1.idx</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git verify-pack -v .git/objects/pack/pack-2021ec3cb18c796fdfca8ef616fb6a20b1449ab1.idx</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 列出之前存在objects里的所有操作数据内容</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 655a12c9b83a029bb46fa852ea15e6affd1587d8 commit 167 117 510</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># ...</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 616dfdb2643c725fa1027ecef76d49d482d9e26d tree 32 43 670</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># ...</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># bfdaa0f1c3415c09d3080063911d155fd7259d18 blob 5 14 853</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 也可以通过后面加 | grep keyword 来搜索所需的内容,如下列出所有commit记录</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git verify-pack -v .git/objects/pack/pack-2021ec3cb18c796fdfca8ef616fb6a20b1449ab1.idx | grep commit</span></p> </blockquote> <p><br></p> <p>git gc ( garbage collect )命令将会收集所有松散对象并将它们存入 pack,合并这些 pack 进一个大的 pack,然后将不被任何 commit 引用并且已存在一段时间 (数月) 的对象删除,除此之外还会将所有引用 (references) 并入一个单独文件(上面有提到随着各种操作,.git下还会产生更多文件夹,.git中的packed-refs文件夹就是这时候产生的)。该命令可能通过修改配置中的 gc.auto 和 gc.autopacklimit 来调整操作阈值。注意:git gc 调用的也是 git prune ,如有需求也可关注这个命令。</p> <p><br></p> <p>至于”info文件夹是干嘛的?”这个问题还未知… 官网的描述也没看懂,也没查到或者在项目中实际出现这个文件夹有存在什么文件,要么等遇到再说?</p> <p><br></p> <p>至此git对象中的三个对象已经知道是咋回事了,还剩个tags对象,简单介绍下。</p> <p><br></p> <p>tags对象通常也是一个commit对象,指的是一个指定了开发者可读名称的一个特殊对象,如有需要也可通过 git cat-file 来解析探索。</p> <p><br></p> <p>其间关系大致如下:</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">|- commit aaaaa…</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> |- tree abbbb…</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> |- blob acccc… (可能是这次修改的)</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> |- blob adddd…(也可能是上次修改的)</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> |- tree aeeee… </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> |- blob affff…</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"> </span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">|- commit bbbbb…</span></p> </blockquote> <p><br></p> <p>关系图的话,这个是git官网的… 和上面的结构是一样的。</p> <p><br></p> <p style="text-align: center;"><img class="" data-ratio="0.74375" src="/upload/a2d1acb004f7c9f4a005fa00a63d7398.png" data-type="png" data-w="800" style="border-width: 0px;border-style: initial;border-color: initial;font-size: 0px;color: transparent;vertical-align: middle;font-family: "Microsoft YaHei", 宋体, "Myriad Pro", Lato, "Helvetica Neue", Helvetica, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);"></p> <p><br></p> <p>基于objects的介绍再回过头来看看”内容、寻址、文件、系统”便比较清晰了:以git对象作为内容,通过唯一的校验和寻址,文件形式存储的一个版本控制系统。</p> <p><br></p> <p>了解完这些,主要还是希望能够运用到实际生产中来解决问题。如 “项目中.git文件为什么这么大?怎么处理?”</p> <p><br></p> <p>可能的处理方案:</p> <p><br></p> <p>1. 执行 git gc ,如果压缩后能达到预期效果,则不做过多处理</p> <p><br></p> <p>2.针对历史记录中对某些大文件的引用,则删除对应引用的对象,操作如下</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git gc</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git count-objects -v</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git verify-pack -v .git/objects/pack/pack-(SHA-1).idx | sort -k 3 -n | tail -5</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 前面用过了git verify-pack,可知第三列信息表示的文件大小,这里用tail取前5个较大文件的记录</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git rev-list --objects --all | grep (SHA-1)</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 使用 git rev-list --objects -all 来查看指定 (SHA-1) 对象信息</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># ce1fed3fdbaf12e816e3028055f9feee57b33b45 xxx.mp4 比如是个视频文件</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git log --pretty=oneline --branches -- xxx.mp4</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 找出哪些 commit 修改/操作了这个文件</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 94cbe08e... add xxx.mp4</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git filter-branch --index-filter 'git rm --cached --ignore-unmatch xxx.mp4' -- 94cbe08e^..</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 删除文件引用,rewrite 信息...</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">rm -rf .git/refs/original</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">rm -rf .git/logs/</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git gc</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 删除 .git/refs/original 和 .git/logs/ ,处理其中对xxx.mp4文件仍存在的引用,之后repack仓库</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git count-objects -v</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 检查下操作后文件大小,或者直接在.git目录下执行 du -h -d 1 查看1级目录/文件的大小</span></p> </blockquote> <p><br></p> <p>3.若还是难处理,或者不好处理,或者不想删除大文件的引用,则备份一份.git,然后初始化git仓库,操作如下</p> <p><br></p> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 除去备份操作,备份操作使用者自定义</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">rm -rf .git</span></p> </blockquote> <blockquote> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git init</span></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);">git remote add origin xxx.git </span></p> <p><br></p> <p><span style="font-size: 12px;color: rgb(136, 136, 136);"># 重新指向新的远程仓库地址,也可根据上文所说修改config文件来指定</span></p> </blockquote> <p><br></p> <p><strong><span style="color: rgb(255, 76, 65);">参考</span></strong></p> <p><br></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p>关于git hooks,参考Customizing-Git-Git-Hooks</p><p>https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks<br></p></li> <li><p>关于更详细的.git文件夹,参考 Gitrepository-layout-objectsinfo</p><p>https://git-scm.com/docs/gitrepository-layout#gitrepository-layout-objectsinfo</p></li> </ul> <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>
作者:微信小助手
<p style="max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-size: 17px;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(255, 0, 0);font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(255, 41, 65);line-height: 22.4px;box-sizing: border-box !important;overflow-wrap: break-word !important;">(点击</span><span style="max-width: 100%;line-height: 22.4px;color: rgb(0, 128, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">上方公众号</span><span style="max-width: 100%;color: rgb(255, 41, 65);line-height: 22.4px;box-sizing: border-box !important;overflow-wrap: break-word !important;">,可快速关注)</span></span></p> <p style="max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-size: 17px;letter-spacing: 0.544px;text-align: justify;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <blockquote style="max-width: 100%;color: rgb(51, 51, 51);font-size: 17px;letter-spacing: 0.544px;text-align: justify;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">来源:虾扯人生</span></p> </blockquote> <p><br></p> <p>今天写代码的时候,用到了线程池,但是由于资源有限,有可能有的任务可能会被丢弃,由于是回调第三方接口,所以我想把丢弃掉的任务信息记录到日志里,方便后续问题定位。这就需要自定义任务拒绝策略。回想到面试遇到的一些线程池问题,决定整理一下相关信息,所以这篇文章就诞生了。</p> <p><br></p> <p><strong><span style="color: rgb(255, 76, 65);">一、如何构建线程池?</span></strong></p> <p><br></p> <p>我相信多数用过线程池的Java程序员都用过Executors来创建线程池,该类提供了几个静态方法,可以快速创建线程池。</p> <p><br></p> <p style="text-align: center;"><img class="" data-ratio="0.7952522255192879" data-s="300,640" data-type="png" data-w="674" src="/upload/b2d44907fee344e3da6375a146988070.png" style="color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;letter-spacing: 0.544px;text-align: center;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;width: 674px !important;visibility: visible !important;"></p> <p><br></p> <p>如上图所示,可以创建四种类型的线程池</p> <p><br></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p>固定线程数量的线程池。</p></li> <li><p>根据需要创建线程的线程池。</p></li> <li><p>执行定时任务的线程池。</p></li> <li><p>单个线程的线程池。</p></li> </ul> <p><br></p> <p>多数情况下,这几种类型的线程池就能满足我们的需要。但是实际上还有一个创建线程池的方法那就是手动构造线程池(ThreadPoolExecutor)</p> <p><br></p> <p><strong><span style="color: rgb(255, 76, 65);">二、ThreadPoolExecutor</span></strong></p> <p><br></p> <p>如果你去看一下前面提到的Executors的几个静态方法的实现,你会发现他们其实就用到了ThreadPoolExecutor,只是根据不同的场景传入了不同的参数。完整的ThreadPoolExecutor总共有七个参数 如图</p> <p><br></p> <p style="text-align: center;"><img class="" data-backh="69" data-backw="558" data-before-oversubscription-url="http://mmbiz.qpic.cn/mmbiz_png/AtmDbftgsMADtLVQMJH5FiaAhOibNUQ3R139znf2t2nT5q4nGTfJZQvfHDZFRC9JYmibQ48SO4UAMIgkNibjGSMOXw/0?wx_fmt=png" data-ratio="0.12380952380952381" data-s="300,640" data-type="png" data-w="630" src="/upload/6b19e38c5c4531ef51d639ca07cbb651.png" style="color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "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;overflow-wrap: break-word !important;width: 558px !important;visibility: visible !important;"></p> <p><br></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p>corePoolSize。核心线程数</p></li> <li><p>maximumPoolSize。最大线程数</p></li> <li><p>keepAliveTime。线程存活时间</p></li> <li><p>unit。 存活时间的单位</p></li> <li><p>workQueue。 工作队列</p></li> <li><p>threadFactory。构造线程池中线程的工厂</p></li> <li><p>handler。任务不能被处理时的拒绝策略</p></li> </ul> <p><br></p> <p><strong><span style="color: rgb(255, 76, 65);">三、工作原理(流程)</span></strong></p> <p><br></p> <p>上面列出的 几个参数,我虽然都给了中文解释,但是如果不结合原理来描述一下他们的具体作用,有些参数我感觉还是不好理解。所以这里就把线程池工作原理和参数一起讲。</p> <p><br></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p>提交任务的时候,判断当前线程池中的存活线程数量是否小于corePoolSize</p></li> <li><p>如果小于corePoolSize,则不管是否有线程处于空闲状态,都会新建一个线程。</p></li> <li><p>如果线程数量已经达到corePoolSize,则将任务扔进队列workQueue</p></li> <li><p>随着任务越来越多,队列可能已经满了,则需要看当前线程是否已经达到了maximumPoolSize,如果没有达到,则创建新的线程,并用它执行该任务。</p></li> <li><p>最坏情况,任务实在太多了,队列已经满了,而线程数量已经达到maximumPoolSize,还有新的任务来,说白了,就是已经满负荷了,任然还有任务需要执行,这个时候就会handler来处理该任务了。</p></li> </ul> <p><br></p> <p>整个工作原理就这样了,标红部分尤其重要,面试稍微深入一点,肯定就会问到这个,一定记住,是先将任务扔进队列,队列满了之后才会继续考虑创建线程。至于为什么要这样设计,可以想一想,想不通可以给我发消息。整个原理说下来,还有3个参数没有提到,这里再说明一下他们的作用</p> <p><br></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p>keepAliveTime。如我们所知,使用线程池的目的就是为了减少线程的创建,因为创建线程本身是比较耗资源的。由于线程本身需要占用资源,有一种情况就是,某个时候线程数量比较多,但是任务没有多少,就会出现有的线程没有活干,所以我们就可以考虑释放掉其资源,但是呢,我们又无法预知未来的任务量,所以我们就准许其空闲一段时间,如果过了这段时间都还是空闲的,那么就会释放掉其资源(就像在公司上班,可能有段时间没活干,老板可能并不会让你走,要是长时间没活干,老板可能就为了节约成本,要裁员了),这个参数就是用指定这段空闲时间的。默认情况下是有超过corePoolSize个线程时,就会用到该值, 但是也可以指定corePoolSize数量之内的线程空闲时是否释放资源(allowCoreThreadTimeout)。(就类似默认情况下,公司肯定只会裁掉非核心员工,但是实在混不走的时候,核心员工可能也会被干掉)</p><p><br></p></li> <li><p>unit 这个参数很好理解,就是单位,就是前面keepAliveTime这个我们准许空闲的时间的单位</p><p><br></p></li> <li><p>factory .其类型为ThreadFactory,顾名思义,就是一个创建Thread的Factory. 该接口只有一个方法,产生一个Thread。通常情况下,我们都只需要使用默认的factory就可以了,但是为了定位问题方便,我们可以为线程池创建的线程设置一个名字,这样看日志的时候就比较方便了。</p></li> </ul> <p><br></p> <p><strong><span style="color: rgb(255, 76, 65);">四、RejectExecutionHandler</span></strong></p> <p><br></p> <p>这个拒绝策略有必要拿出来单独说一下,我今天就是实现了该接口,从而满足了业务需要。</p> <p><br></p> <p>为什么我需要自己实现该接口,而采用Executors静态方法时,并没有让传入该参数呢?实际上Jdk本身提供了四种策略,分别是</p> <p><br></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p>AbortPolicy。会抛出异常</p></li> <li><p>CallerRunnerPolicy。在调用execute的方法中执行被拒绝的任务</p></li> <li><p>DiscardOldestPolicy。丢掉队列中最老的任务,然后重试</p></li> <li><p>DiscardPolicy。直接丢掉该任务</p></li> </ul> <p><br></p> <p>这四种策略是ThredPoolExecutor的内部类,实现都比较简单,有兴趣的可以看一下。我今天的实现方式也很简单,实际上就是在discardPolicy的基础上增加日志记录。</p> <p><br></p> <p><strong><span style="color: rgb(255, 76, 65);">五、其他</span></strong></p> <p><br></p> <p>前面说了其工作原理,但是看了一下源代码,其实和描述的原理并不完全一致。主要在处理队列大小的时候,主要是对正在运行的线程数量还个判断,不能超过指定的值,当然这个值比较大,我们一般不会达到这个值,至于具体原因我也么去继续深入研究。</p> <p><br></p> <p>其次就是参数设置,可能需要具体业务场景,任务数量,任务执行速度来调整,并没有一个固定的值。只是记得一定要设置队列大小,不然就使用了一个无界队列,可能就是会内存爆掉。</p> <p><br></p> <p>实际使用场景下,还有一些可以优化的地方,比如对不同类型的任务创建不同的线程池, 比如有的线程比较耗时,有的很快,如果放在同一个线程池里面执行,可能导致队列很快就满了,本来该很快执行完的任务却一直得不到执行。</p> <p><br></p> <p>另外还有ThreadPoolExecutor还提供了一些hook方法,如有需要可以使用</p> <p><br></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p>beforeExecute() 任务执行之前调用</p></li> <li><p>afterExecute() 任务执行之后调用</p></li> </ul> <p><br></p> <p>虽然有点标题党,说是深入理解,其实也并不是特别深入,但是基本上这篇文章的内容掌握过后,个人觉得起码90%以上的问题都能对答如流了。还有10%在哪里? 可以去看一下newCachedThreadPool的实现,他使用的队列不一样。还有就是想一想,如果实现线程存活的功能,让自己实现,怎么来做。另外可能就是真的需要去看一下源码,把具体的worker创建运行过程都搞透彻了。</p> <p><br></p> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box;color: rgb(51, 51, 51);font-size: 17px;letter-spacing: 0.544px;text-align: justify;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;"> <section class="" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;box-sizing: border-box;text-align: left;overflow-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;overflow-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;"> <section class="" style="max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;"> <section class="" style="max-width: 100%;box-sizing: border-box;color: rgb(93, 93, 93);overflow-wrap: break-word !important;"> <p class="" style="max-width: 100%;box-sizing: border-box;min-height: 1em;font-size: 13px;overflow-wrap: break-word !important;">【关于投稿】</p> <p class="" style="max-width: 100%;box-sizing: border-box;min-height: 1em;font-size: 13px;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p class="" style="max-width: 100%;box-sizing: border-box;min-height: 1em;font-size: 13px;overflow-wrap: break-word !important;">如果大家有原创好文投稿,请直接给公号发送留言。</p> <p class="" style="max-width: 100%;box-sizing: border-box;min-height: 1em;font-size: 13px;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p class="" style="max-width: 100%;box-sizing: border-box;min-height: 1em;font-size: 13px;overflow-wrap: break-word !important;"><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;overflow-wrap: break-word !important;">① 留言格式:</span><br style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;overflow-wrap: break-word !important;">【投稿】+《 文章标题》+ 文章链接</span><br style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;overflow-wrap: break-word !important;">② 示例:</span><br style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;overflow-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;overflow-wrap: break-word !important;"><br style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(53, 53, 53);box-sizing: border-box !important;overflow-wrap: break-word !important;">③ 最后请附上您的个人简介哈~</span></span></p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-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-size: 17px;letter-spacing: 0.544px;text-align: justify;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-size: 17px;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;color: rgb(255, 169, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">看完本文有收获?请转发分享给更多人</span></p> <p style="max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-size: 17px;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(255, 169, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">关注「ImportNew」,提升Java技能</strong></p> <p style="max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);font-size: 17px;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-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;overflow-wrap: break-word !important;visibility: visible !important;width: 600px !important;"></p>
作者:じ☆ve宝贝
## 8.代理模式(Proxy) 其实每个模式名称就表明了该模式的作用,代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。再如我们有的时候打官司,我们需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们的想法。先来看看关系图:  根据上文的阐述,代理模式就比较容易的理解了,我们看下代码: ``` public interface Sourceable { public void method(); } ``` ``` public class Source implements Sourceable { @Override public void method() { System.out.println("the original method!"); } } ``` ``` public class Proxy implements Sourceable { private Source source; public Proxy(){ super(); this.source = new Source(); } @Override public void method() { before(); source.method(); atfer(); } private void atfer() { System.out.println("after proxy!"); } private void before() { System.out.println("before proxy!"); } } ``` 测试类: ``` public class ProxyTest { public static void main(String[] args) { Sourceable source = new Proxy(); source.method(); } } ``` 输出: before proxy! the original method! after proxy! 代理模式的应用场景: 如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法: 1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。 2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。 使用代理模式,可以将功能划分的更加清晰,有助于后期维护!