文章列表

Java jar 如何防止被反编译

作者:微信小助手

<p style="outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;font-size: 14px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">java作为解释型的语言,其高度抽象的特</span><span style="outline: 0px;max-width: 100%;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;font-size: 14px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">性意味其很容易被反编译,容易被反编译,自然有防止反编译措施存在。</span><span style="outline: 0px;max-width: 100%;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;font-size: 14px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">今天就拜读了一篇相关的文章,受益匪浅,知彼知己嘛!</span><span style="outline: 0px;max-width: 100%;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;font-size: 14px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">!</span><span style="outline: 0px;max-width: 100%;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;font-size: 14px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">之所以会对java的反编译感兴趣,那是因为自己在学习的过程中,常常需要借鉴一下别人的成果(你懂的...)。</span><span style="outline: 0px;max-width: 100%;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;font-size: 14px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">或许反编译别人的代码不怎么道德,这个嘛......</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin-bottom: 16px;outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin-bottom: 16px;outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">废话不多说,正文如下:</span></p> <p style="margin: 5px auto;outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">常用的保护技术</span></p> <p style="margin: 5px auto;outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">由于Java字节码的抽象级别较高,因此它们较容易被反编译。本节介绍了几种常用的方法,用于保护Java字节码不被反编译。通常,这些方法不能够绝对防止程序被反编译,而是加大反编译的难度而已,因为这些方法都有自己的使用环境和弱点。</span></p> <p style="margin: 5px auto;outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px !important;"><span style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-family: mceinline;font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">1. 隔离Java程序</span>  </span></p> <p style="margin: 5px auto;outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">最简单的方法就是让用户不能够访问到Java Class程序,这种方法是最根本的方法,具体实现有多种方式。例如,开发人员可以将关键的Java Class放在服务器端,客户端通过访问服务器的相关接口来获得服务,而不是直接访问Class文件。这样黑客就没有办法反编译Class文件。目前,通过接口提供服务的标准和协议也越来越多,例如 HTTP、Web Service、RPC等。但是有很多应用都不适合这种保护方式,例如对于单机运行的程序就无法隔离Java程序。这种保护方式见图1所示。</span></p> <p style="outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages wxw-img" data-fileid="309632677" data-galleryid="" data-ratio="0.5531914893617021" data-s="300,640" src="/upload/f2e77283e293989b103c334cafc14f7e.png" data-type="png" data-w="470" style="outline: 0px;border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);box-sizing: border-box !important;overflow-wrap: break-word !important;background-color: rgb(238, 237, 235) !important;background-size: 22px !important;background-position: center center !important;background-repeat: no-repeat !important;width: 470px !important;visibility: visible !important;"></p> <p style="margin: 5px auto;outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 图1隔离Java程序示意图   <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span><span style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">2. 对Class文件进行加密</span> </span><span style="outline: 0px;max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 为了防止Class文件被直接反编译,许多开发人员将一些关键的Class文件进行加密,例如对注册码、序列号管理相关的类等。在使用这些被加密的类之前,程序首先需要对这些类进行解密,而后再将这些类装载到JVM当中。这些类的解密可以由硬件完成,也可以使用软件完成。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  在实现时,开发人员往往通过自定义ClassLoader类来完成加密类的装载(注意由于安全性的原因,Applet不能够支持自定义的 ClassLoader)。自定义的ClassLoader首先找到加密的类,而后进行解密,最后将解密后的类装载到JVM当中。在这种保护方式中,自定义的ClassLoader是非常关键的类。由于它本身不是被加密的,因此它可能成为黑客最先攻击的目标。如果相关的解密密钥和算法被攻克,那么被加密的类也很容易被解密。这种保护方式示意图见图2。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp; </span></p> <p style="outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages wxw-img" data-fileid="309632680" data-galleryid="" data-ratio="0.4954128440366973" data-s="300,640" src="/upload/8f7907379634779f40a3d2cab0e53af8.png" data-type="png" data-w="545" style="outline: 0px;border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);box-sizing: border-box !important;overflow-wrap: break-word !important;background-color: rgb(238, 237, 235) !important;background-size: 22px !important;background-position: center center !important;background-repeat: no-repeat !important;height: 271.514px !important;width: 545px !important;"></p> <p style="margin: 5px auto;outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 图2 对Class文件进行加密示意图</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin: 5px auto;outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">3. 转换成本地代码</span>  </span><span style="outline: 0px;max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">将程序转换成本地代码也是一种防止反编译的有效方法。因为本地代码往往难以被反编译。开发人员可以选择将整个应用程序转换成本地代码,也可以选择关键模块转换。如果仅仅转换关键部分模块,Java程序在使用这些模块时,需要使用JNI技术进行调用。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  当然,在使用这种技术保护Java程序的同时,也牺牲了Java的跨平台特性。对于不同的平台,我们需要维护不同版本的本地代码,这将加重软件支持和维护的工作。不过对于一些关键的模块,有时这种方案往往是必要的。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  为了保证这些本地代码不被修改和替代,通常需要对这些代码进行数字签名。在使用这些本地代码之前,往往需要对这些本地代码进行认证,确保这些代码没有被黑客更改。如果签名检查通过,则调用相关JNI方法。这种保护方式示意图见图3。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></p> <p style="outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages wxw-img" data-fileid="309632679" data-galleryid="" data-ratio="0.5465346534653466" data-s="300,640" src="/upload/7d69c127ddfffa1a4024e668b06caeb9.png" data-type="png" data-w="505" style="outline: 0px;border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);box-sizing: border-box !important;overflow-wrap: break-word !important;background-color: rgb(238, 237, 235) !important;background-size: 22px !important;background-position: center center !important;background-repeat: no-repeat !important;height: 277.36px !important;width: 505px !important;"></p> <p style="margin: 5px auto;outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;  <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 图3 转换成本地代码示意图  </span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin: 5px auto;outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px !important;"><span style="outline: 0px;max-width: 100%;font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">4. 代码混淆</span><span style="outline: 0px;max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">代码混淆是对Class文件进行重新组织和处理,使得处理后的代码与处理前代码完成相同的功能(语义)。但是混淆后的代码很难被反编译,即反编译后得出的代码是非常难懂、晦涩的,因此反编译人员很难得出程序的真正语义。从理论上来说,黑客如果有足够的时间,被混淆的代码仍然可能被破解,甚至目前有些人正在研制反混淆的工具。但是从实际情况来看,由于混淆技术的多元化发展,混淆理论的成熟,经过混淆的Java代码还是能够很好地防止反编译。下面我们会详细介绍混淆技术,因为混淆是一种保护Java程序的重要技术。图4是代码混淆的示图。&nbsp;&nbsp;  </span></p> <p style="outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages wxw-img" data-fileid="309632676" data-galleryid="" data-ratio="0.1953781512605042" data-s="300,640" src="/upload/722033c4dea18e3e0fab50c111bf3f6a.png" data-type="png" data-w="476" style="outline: 0px;border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);box-sizing: border-box !important;overflow-wrap: break-word !important;background-color: rgb(238, 237, 235) !important;background-size: 22px !important;background-position: center center !important;background-repeat: no-repeat !important;height: 95.4139px !important;width: 476px !important;"></p> <p style="margin: 5px auto;outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 图4 代码混淆示意图   <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin: 5px auto;outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;"><em style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">几种技术的总结&nbsp;</em></span>  <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">以上几种技术都有不同的应用环境,各自都有自己的弱点,表1是相关特点的比较。  <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">混淆技术介绍<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  表1 不同保护技术比较表<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></p> <p style="outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages wxw-img" data-fileid="309632678" data-galleryid="" data-ratio="0.924908424908425" data-s="300,640" src="/upload/5b1e69cc1d1497989b7f892248eea7c0.png" data-type="png" data-w="546" style="outline: 0px;border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);box-sizing: border-box !important;overflow-wrap: break-word !important;background-color: rgb(238, 237, 235) !important;background-size: 22px !important;background-position: center center !important;background-repeat: no-repeat !important;height: 505.225px !important;width: 546px !important;"></p> <p style="margin: 5px auto;outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp; &nbsp; &nbsp;到目前为止,对于Java程序的保护,混淆技术还是最基本的保护方法。Java混淆工具也非常多,包括商业的、免费的、开放源代码的。Sun公司也提供了自己的混淆工具。它们大多都是对Class文件进行混淆处理,也有少量工具首先对源代码进行处理,然后再对Class进行处理,这样加大了混淆处理的力度。目前,商业上比较成功的混淆工具包括JProof公司的1stBarrier系列、Eastridge公司的JShrink和 4thpass.com的SourceGuard等。主要的混淆技术按照混淆目标可以进行如下分类,它们分别为符号混淆(Lexical Obfuscation)、数据混淆(Data Obfuscation)、控制混淆(Control Obfuscation)、预防性混淆(Prevent Transformation)。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  <span style="outline: 0px;max-width: 100%;font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">符号混淆</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  在Class中存在许多与程序执行本身无关的信息,例如方法名称、变量名称,这些符号的名称往往带有一定的含义。例如某个方法名为 getKeyLength(),那么这个方法很可能就是用来返回Key的长度。符号混淆就是将这些信息打乱,把这些信息变成无任何意义的表示,例如将所有的变量从vairant_001开始编号;对于所有的方法从method_001开始编号。这将对反编译带来一定的困难。对于私有函数、局部变量,通常可以改变它们的符号,而不影响程序的运行。但是对于一些接口名称、公有函数、成员变量,如果有其它外部模块需要引用这些符号,我们往往需要保留这些名称,否则外部模块找不到这些名称的方法和变量。因此,多数的混淆工具对于符号混淆,都提供了丰富的选项,让用户选择是否、如何进行符号混淆。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  <span style="outline: 0px;max-width: 100%;font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">数据混淆</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;</span></p> <p style="outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages wxw-img" data-fileid="309632684" data-galleryid="" data-ratio="0.44529262086513993" data-s="300,640" data-type="png" data-w="393" src="/upload/c91169eabe35a8f01577ce5e7c08e84b.png" style="outline: 0px;border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);box-sizing: border-box !important;overflow-wrap: break-word !important;background-color: rgb(238, 237, 235) !important;background-size: 22px !important;background-position: center center !important;background-repeat: no-repeat !important;height: 176.664px !important;visibility: visible !important;width: 393px !important;"></p> <p style="margin: 5px auto;outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">  图5 改变数据访问<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  数据混淆是对程序使用的数据进行混淆。混淆的方法也有多种,主要可以分为改变数据存储及编码(Store and Encode Transform)、改变数据访问(Access Transform)。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  改变数据存储和编码可以打乱程序使用的数据存储方式。例如将一个有10个成员的数组,拆开为10个变量,并且打乱这些变量的名字;将一个两维数组转化为一个一维数组等。对于一些复杂的数据结构,我们将打乱它的数据结构,例如用多个类代替一个复杂的类等。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  另外一种方式是改变数据访问。例如访问数组的下标时,我们可以进行一定的计算,图5就是一个例子。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  在实践混淆处理中,这两种方法通常是综合使用的,在打乱数据存储的同时,也打乱数据访问的方式。经过对数据混淆,程序的语义变得复杂了,这样增大了反编译的难度。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  <span style="outline: 0px;max-width: 100%;font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">控制混淆</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  控制混淆就是对程序的控制流进行混淆,使得程序的控制流更加难以反编译,通常控制流的改变需要增加一些额外的计算和控制流,因此在性能上会给程序带来一定的负面影响。有时,需要在程序的性能和混淆程度之间进行权衡。控制混淆的技术最为复杂,技巧也最多。这些技术可以分为如下几类:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  增加混淆控制通过增加额外的、复杂的控制流,可以将程序原来的语义隐藏起来。例如,对于按次序执行的两个语句A、B,我们可以增加一个控制条件,以决定B的执行。通过这种方式加大反汇编的难度。但是所有的干扰控制都不应该影响B的执行。图6就给出三种方式,为这个例子增加混淆控制。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;</span></p> <p style="outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages wxw-img" data-fileid="309632683" data-galleryid="" data-ratio="0.32092198581560283" data-s="300,640" src="/upload/98089f3f41224d8f4b02c7a1d97532db.png" data-type="png" data-w="564" style="outline: 0px;border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);box-sizing: border-box !important;overflow-wrap: break-word !important;background-color: rgb(238, 237, 235) !important;background-size: 22px !important;background-position: center center !important;background-repeat: no-repeat !important;height: 183.037px !important;width: 564px !important;"></p> <p style="margin: 5px auto;outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">  图6 增加混淆控制的三种方式<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  控制流重组重组控制流也是重要的混淆方法。例如,程序调用一个方法,在混淆后,可以将该方法代码嵌入到调用程序当中。反过来,程序中的一段代码也可以转变为一个函数调用。另外,对于一个循环的控制流,为可以拆分多个循环的控制流,或者将循环转化成一个递归过程。这种方法最为复杂,研究的人员也非常多。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  <span style="outline: 0px;max-width: 100%;font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">预防性混淆</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  这种混淆通常是针对一些专用的反编译器而设计的,一般来说,这些技术利用反编译器的弱点或者Bug来设计混淆方案。例如,有些反编译器对于 Return后面的指令不进行反编译,而有些混淆方案恰恰将代码放在Return语句后面。这种混淆的有效性对于不同反编译器的作用也不太相同的。一个好的混淆工具,通常会综合使用这些混淆技术。</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin: 5px auto;outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin: 5px auto;outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><em style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">案例分析</span></em><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  在实践当中,保护一个大型Java程序经常需要综合使用这些方法,而不是单一使用某一种方法。这是因为每种方法都有其弱点和应用环境。综合使用这些方法使得Java程序的保护更加有效。另外,我们经常还需要使用其它的相关安全技术,例如安全认证、数字签名、PKI等。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  本文给出的例子是一个Java应用程序,它是一个SCJP(Sun Certificate Java Programmer)的模拟考试软件。该应用程序带有大量的模拟题目,所有的题目都被加密后存储在文件中。由于它所带的题库是该软件的核心部分,所以关于题库的存取和访问就成为非常核心的类。一旦这些相关的类被反编译,则所有的题库将被破解。现在,我们来考虑如何保护这些题库及相关的类。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  在这个例子中,我们考虑使用综合保护技术,其中包括本地代码和混淆技术。因为该软件主要发布在Windows上,因此转换成本地代码后,仅仅需要维护一个版本的本地代码。另外,混淆对Java程序也是非常有效的,适用于这种独立发布的应用系统。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  在具体的方案中,我们将程序分为两个部分,一个是由本地代码编写的题库访问的模块,另外一个是由Java开发的其它模块。这样可以更高程度地保护题目管理模块不被反编译。对于Java开发的模块,我们仍然要使用混淆技术。该方案的示意图参见图7。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></p> <p style="outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages wxw-img" data-fileid="309632681" data-galleryid="" data-ratio="0.35110294117647056" data-s="300,640" src="/upload/7d223d77ea413f95c0a3ca738b84217f.png" data-type="png" data-w="544" style="outline: 0px;border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);box-sizing: border-box !important;overflow-wrap: break-word !important;background-color: rgb(238, 237, 235) !important;background-size: 22px !important;background-position: center center !important;background-repeat: no-repeat !important;height: 192.947px !important;width: 544px !important;"></p> <p style="margin: 5px auto;outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  图7 SCJP保护技术方案图<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  对于题目管理模块,由于程序主要在Windows下使用,所以使用C++开发题库访问模块,并且提供了一定的访问接口。为了保护题库访问的接口,我们还增加了一个初始化接口,用于每次使用题库访问接口之前的初始化工作。它的接口主要分为两类:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  <span style="outline: 0px;max-width: 100%;font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">1. 初始化接口</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  在使用题库模块之前,我们必须先调用初始化接口。在调用该接口时,客户端需要提供一个随机数作为参数。题库管理模块和客户端通过这个随机数,按一定的算法同时生成相同的SessionKey,用于加密以后输入和输出的所有数据。通过这种方式,只有授权(有效)的客户端才能够连接正确的连接,生成正确的 SessionKey,用于访问题库信息。非法的客户很难生成正确的SessionKey,因此无法获得题库的信息。如果需要建立更高的保密级别,也可以采用双向认证技术。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  <span style="outline: 0px;max-width: 100%;font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">2. 数据访问接口</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">  认证完成之后,客户端就可以正常的访问题库数据。但是,输入和输出的数据都是由SessionKey所加密的数据。因此,只有正确的题库管理模块才能够使用题库管理模块。图8时序图表示了题库管理模块和其它部分的交互过程。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;  </span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="outline: 0px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages wxw-img" data-fileid="309632682" data-galleryid="" data-ratio="0.6238859180035651" data-s="300,640" src="/upload/534f2979f935c3a91db5da9c2306e6fd.png" data-type="png" data-w="561" style="outline: 0px;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 561px !important;"></p> <section style="margin-right: 8px;margin-left: 8px;white-space: normal;caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-size-adjust: auto;background-color: rgb(255, 255, 255);text-align: left;"> <span style="color: rgb(145, 145, 145);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 14px;letter-spacing: 0.544px;"><br></span> <br> </section> <section style="white-space: normal;"> <section style="margin-right: 8px;margin-left: 8px;line-height: 1.75em;text-align: left;"> <section powered-by="xiumi.us" style="text-align: center;color: rgb(62, 71, 83);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;"> <section> <section> <section> <section powered-by="xiumi.us"> <section> <p style="margin-right: 16px;margin-left: 16px;background-color: rgb(255, 255, 255);letter-spacing: 1.5px;line-height: 1.5em;font-family: -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;"><strong><span style="font-size: 12px;caret-color: red;letter-spacing: 1px;"><strong style="font-size: 17px;letter-spacing: 0.544px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"><span style="font-size: 12px;">— 本文结束 —</span></strong></span></strong></p> </section> </section> </section> </section> </section> </section> </section> </section>

基于 Prometheus、InfluxDB 与 Grafana 打造监控平台

作者:微信小助手

<section style="font-size: 16px;"> <section data-mpa-template="t" mpa-from-tpl="t" style="outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-mpa-template="t" mpa-from-tpl="t" style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;">在本文中,我将把几个常用的监控部分给梳理一下。前面我们提到过,在性能监控图谱中,有操作系统、应用服务器、中间件、队列、缓存、数据库、网络、前端、负载均衡、Web 服务器、存储、代码等很多需要监控的点。显然这些监控点不能在一个专栏中全部覆盖并一一细化,我只能找最常用的几个,做些逻辑思路的说明,同时也把具体的实现描述出来。如果你遇到了其他的组件,也需要一一实现这些监控。</p> <p style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;">在本篇中,主要想说明白下图的这个监控逻辑。</p> <p style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;text-align: center;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages wxw-img" data-fileid="502258882" data-ratio="0.41574074074074074" data-type="png" data-w="1080" style="margin-bottom: 15px;outline: 0px;max-width: 625px;box-sizing: border-box;vertical-align: middle;border-width: 0px;border-style: initial;border-color: initial;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;height: auto !important;" src="/upload/a0c23638d27492ab0d1f1cacff39e1ca.png"></p> <p style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;">这应该是现在最流行的一套监控逻辑了吧。我今天把常见的使用 Grafana、Prometheus、InfluxDB、Exporters 的数据展示方式说一下,如果你刚进入性能测试领域,也能有一个感性的认识。</p> <p style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;">有测试工具,有监控工具,才能做后续的性能分析和瓶颈定位,所以有必要把这些工具的逻辑跟你摆一摆。</p> <p style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;">所有做性能的人都应该知道一点,不管数据以什么样的形式展示,最要紧的还是看数据的来源和含义,以便做出正确的判断。</p> <p style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;">我先说明一下 JMeter 和 node_exporter 到 Grafana 的数据展示逻辑。至于其他的 Exporter,我就不再解释这个逻辑了,只说监控分析的部分。</p> </section> </section> <section style="outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section data-mpa-template="t" mpa-from-tpl="t" style="outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;color: rgb(60, 60, 60);font-size: 16px;font-weight: bold;letter-spacing: 1px;text-align: center;line-height: 1.8;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;z-index: 10000;margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> JMeter + InfluxDB + Grafana 的数据展示逻辑 </section> <section style="outline: 0px;max-width: 100%;margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-fileid="502258883" data-ratio="0.053125" data-type="png" data-w="640" style="outline: 0px;color: rgb(60, 60, 60);font-weight: bold;letter-spacing: 1px;text-align: center;font-size: 15px;display: inline-block;left: 0px;transform: rotateX(60deg);margin-top: 5px !important;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 632px !important;height: auto !important;" src="/upload/2cb3b6f138411260440626ddf3a7f40b.png"> </section> <section style="outline: 0px;max-width: 100%;margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> </section> <section data-mpa-template="t" mpa-from-tpl="t" style="outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-mpa-template="t" mpa-from-tpl="t" style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 一般情况下,我们用 JMeter 做压力测试时,都是使用 JMeter 的控制台来查看结果。如下图所示: </section> <section style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section mpa-from-tpl="t" mpa-is-content="t" style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="outline: 0px;max-width: 100%;text-align: center;margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img class="rich_pages wxw-img" data-fileid="502258887" data-ratio="0.33425925925925926" data-type="png" data-w="1080" style="outline: 0px;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;height: auto !important;" src="/upload/9349dad901e2b8bd5eb815b1a422032b.png"> </section> </section> <section style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 或者装个插件来看结果: </section> <section style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section mpa-from-tpl="t" mpa-is-content="t" style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="outline: 0px;max-width: 100%;text-align: center;margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img class="rich_pages wxw-img" data-fileid="502258886" data-ratio="0.42592592592592593" data-type="png" data-w="1080" style="outline: 0px;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;height: auto !important;" src="/upload/f3683b35c0e70b31459d4d3dcf8b62d5.png"> </section> </section> <section style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 或者用 JMeter 来生成 HTML: </section> <section style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section mpa-from-tpl="t" mpa-is-content="t" style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="outline: 0px;max-width: 100%;text-align: center;margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-fileid="502258885" data-ratio="0.5294705294705294" data-type="png" data-w="1001" style="outline: 0px;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;height: auto !important;" src="/upload/5229ea2c84b9991b261e8d8042f147dd.png"> </section> </section> <section style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 这样看都没有问题,我们在前面也强调过,对于压力工具来说,我们最多只关心三条曲线的数据:TPS(T 由测试目标定义)、响应时间、错误率。这里的错误率还只是辅助排查问题的曲线,没有问题时,只看 TPS 和响应时间即可。 </section> <section style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 不过采取以上三种方式有几个方面的问题。 </section> <section style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;font-size: 15px;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);margin-left: 8px;margin-right: 8px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </section> <section data-mpa-template="t" mpa-from-tpl="t" style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-mpa-template="t" mpa-from-tpl="t" style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <ol class="list-paddingleft-2" mpa-from-tpl="t" style="outline: 0px;max-width: 100%;letter-spacing: 0.544px;margin-left: 8px;margin-right: 8px;overflow-wrap: break-word !important;"> <li style="outline: 0px;max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">整理结果时比较浪费时间。</span></p></li> <li style="outline: 0px;max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">在 GUI 用插件看曲线,做高并发时并不现实。</span></p></li> <li style="outline: 0px;max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;letter-spacing: 1px;line-height: 1.8;color: rgb(60, 60, 60);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI

6000字 | 深入理解 Ribbon 的架构原理(文末送会员)

作者:微信小助手

<p style="text-align: center;" data-mpa-powered-by="yiban.io"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.4214239897370109" data-s="300,640" src="/upload/da10343fbf4fbd1e51760696c0b993b2.png" data-type="png" data-w="1559" style=""></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;color: rgb(53, 53, 53);word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">大家好,我是悟空。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">今天我们来看下微服务中非常重要的一个组件:<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">Ribbon</code>。它作为负载均衡器在分布式网络中扮演着非常重要的角色。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">本篇主要内容如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.7287784679089027" src="/upload/49ebd1fc8d8c538b1cc6320a81b44382.png" data-type="png" data-w="966" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">在介绍 Ribbon 之前,不得不说下负载均衡这个比较偏僻的名词。为什么说它偏僻了,因为在面试中,聊得最多的是消息队列和缓存来提高系统的性能,支持高并发,很少有人会问负载均衡,究其原因,负载均衡的组件选择和搭建一般都是运维团队或者架构师去做的,开发人员确实很少接触到。<span style="color: rgb(255, 104, 39);">不过没关系,我们不止有 CRUD,还要有架构思维。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">简单来说,负载均衡就是将网络流量(负载)分摊到不同的网络服务器(可以平均分配,也可以不平均),系统就可以实现服务的水平横向扩展。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">那么如果让你设计一个负载均衡组件,你会怎么设计?</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">我们需要考虑这几个因素:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 如何获取及同步服务器列表?涉及到与注册中心的交互。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 如何将负载进行分摊?涉及到分摊策略。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 如何将客户端请求进行拦截然后选择服务器进行转发?涉及到请求拦截。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">抱着这几个问题,我们从负载均衡的原理 + Ribbon 的架构来学习如何设计一个负载均衡器,相信会带给你一些启发。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">一、负载均衡</span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">1.1 概念</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">之前我详细讲解了何为高可用<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451956637&amp;idx=1&amp;sn=faf59d9804f8fc49045cf9916e2a613a&amp;chksm=8d1c1a02ba6b93143bd4f12af37a8650160c5d070cd688b64fa2b4b0271c23dc871c0e1b0280&amp;scene=21#wechat_redirect" textvalue="B 站崩了,总结下「高可用」和「异地多活」" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" style="text-decoration: underline;" data-linktype="2">B 站崩了,总结下「高可用」和「异地多活」</a></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">里面没有涉及到负载均衡机制,其实负载均衡也是高可用网络的关键组件。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.476831091180867" src="/upload/e67fa9a53e40a291f41e11373587b099.png" data-type="png" data-w="669" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">负载均衡的<span style="color: rgb(255, 104, 39);"><strong>两个基本点</strong></span>:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 选择哪个服务器来处理客户端请求。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 将客户端请求转发出去。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;"><span style="color: rgb(255, 104, 39);"><strong>一个核心原理</strong></span>:通过硬件或软件的方式维护一个服务列表清单。当用户发送请求时,会将请求发送给负载均衡器,然后根据负载均衡算法从可用的服务列表中选出一台服务器的地址,将请求进行转发,完成负载功能。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">1.2 负载均衡的特性</span><span style="display: none;"></span></h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.8116504854368932" src="/upload/adac3e6d2b5eebc1238fb80a237dde1f.png" data-type="png" data-w="515" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> 负载均衡的特性 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">高性能</span>:可根据不同的分配规则自动将流量进行分摊。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">可扩展性</span>:可以很方便增加集群中设备或链路的数量。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">高可靠性</span>:系统中某个设备或链路发生故障,不会导致服务中断。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">易配置性</span>:配置和维护方便。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">透明性</span>:用户感知不到如何进行负载均衡的,也不用关心负载均衡。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">1.3 负载均衡分类</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">负载均衡技术可以按照软件或硬件进行<span style="color: rgb(255, 104, 39);">分类</span>,也可以按照服务器列表存放的位置划分为服务端负载和客户端负载均衡。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.48518518518518516" src="/upload/4f9ecb9959c178076b1154b822cbc7b7.png" data-type="png" data-w="540" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 18px;"><span style="display: none;"></span>1.3.1 硬件负载均衡<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">F5 就是常见的硬件负载均衡产品。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">优点:性能稳定,具备很多软件负载均衡不具备的功能,如应用交换,会话交换、状态监控等。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">缺点:设备价格昂贵、配置冗余,没有软件负载均衡灵活,不能满足定制化需求。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 18px;"><span style="display: none;"></span>1.3.2 软件负载均衡<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">Nginx:性能好,可以负载超过 1W。工作在网络的7层之上,可以针对http应用做一些分流的策略。Nginx也可作为静态网页和图片服务器。Nginx仅能支持http、https和Email协议。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">LVS(Linux Virtual Server):是一个虚拟服务器集群系统,采用 IP 地址均衡技术和内容请求分发技术实现负载均衡。接近硬件设备的网络吞吐和连接负载能力。抗负载能力强、是工作在网络4层之上仅作分发之用。自身有完整的双机热备方案,如LVS+Keepalived。软件本身不支持正则表达式处理,不能做动静分离。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 18px;"><span style="display: none;"></span>1.3.3 服务端负载均衡<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">Nginx 和 F5 都可以划分到服务端的负载均衡里面,后端的服务器地址列表是存储在后端服务器中或者存在专门的 Nginx 服务器或 F5 上。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">服务器的地址列表的来源是通过注册中心或者手动配置的方式来的。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 18px;"><span style="display: none;"></span>1.3.4 客户端负载均衡<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">终于轮到 Ribbon 登场了,它属于客户端负载均衡器,客户端自己维护一份服务器的地址列表。这个维护的工作就是由 Ribbon 来干的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">Ribbon 会从 Eureka Server 读取服务信息列表,存储在 Ribbon 中。如果服务器宕机了,Ribbon 会从列表剔除宕机的服务器信息。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">Ribbon 有多种负载均衡算法,我们可以自行设定规则从而请求到指定的服务器。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">二、 均衡策略</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">上面已经介绍了各种负载均衡分类,接下来我们来看下这些负载均衡器如何通过负载均衡策略来选择服务器处理客户端请求。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">常见的均衡策略如下。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">2.1 轮循均衡(Round Robin)</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">原理:如果给服务器从 0 到 N 编号,轮询均衡策略会从 0 开始依次选择一个服务器作为处理本次请求的服务器。-</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">场景:适合所有父亲都有相同的软硬件配置,且请求频率相对平衡。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">2.2 权重轮询均衡(Weighted Round Robin)</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">原理:按照服务器的不同处理能力,给服务器分配不同的权重,然后请求会按照权重分配给不同的服务器。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">场景:服务器的性能不同,充分利用高性能的服务器,同时也能照顾到低性能的服务器。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">2.3 随机均衡(Random)</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">原理:将请求随机分配给不同的服务器。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">场景:适合客户端请求的频率比较随机的场景。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">2.4 响应速度均衡(Response Time)</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">原理:负载均衡设备对每个服务器发送一个探测请求,看看哪台服务器的响应速度更快,</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">场景:适合服务器的响应性能不断变化的场景。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">注意:响应速度是针对负载均衡设备和服务器之间的。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">三、Ribbon 核心组件</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">接下来就是我们的<span style="color: rgb(255, 104, 39);"><strong>重头戏</strong></span>了,来看下 Ribbon 这个 Spring Cloud 中负载均衡组件。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">Ribbon 主要有五大功能组件:ServerList、Rule、Ping、ServerListFilter、ServerListUpdater。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.5051792828685259" src="/upload/b54fa7e4beb7012dfbecc4c34f4e1f9c.png" data-type="png" data-w="1255" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> Ribbon 核心组件 </figcaption> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">3.1 负载均衡器 LoadBalancer</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">用于管理负载均衡的组件。初始化的时候通过加载 YMAL 配置文件创建出来的。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">3.2 服务列表 ServerList</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">ServerList 主要用来获取所有服务的地址信息,并存到本地。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">根据获取服务信息的方式不同,又分为静态存储和动态存储。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">静态存储:从配置文件中获取服务节点列表并存储到本地。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">动态存储:从注册中心获取服务节点列表并存储到本地</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">3.3 服务列表过滤 ServerListFilter</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">将获取到的服务列表按照过滤规则过滤。</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;font-size: 15px;">通过 Eureka 的分区规则对服务实例进行过滤。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;font-size: 15px;">比较服务实例的通信失败数和并发连接数来剔除不够健康的实例。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;font-size: 15px;">根据所属区域过滤出同区域的服务实例。</p> </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">3.4 服务列表更新 ServerListUpdater</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">服务列表更新就是 Ribbon 会从注册中心获取最新的注册表信息。是由这个接口 ServerListUpdater 定义的更新操作。而它有两个实现类,也就是有两种更新方式:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 通过定时任务进行更新。由这个实现类 PollingServerListUpdater 做到的。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 利用 Eureka 的事件监听器来更新。由这个实现类 EurekaNotificationServerListUpdater 做到的。 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">3.5 心跳检测 Ping</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">IPing 接口类用来检测哪些服务可用。如果不可用了,就剔除这些服务。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">实现类主要有这几个:PingUrl、PingConstant、NoOpPing、DummyPing、NIWSDiscoveryPing。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">心跳检测策略对象 IPingStrategy,默认实现是轮询检测。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">3.6 负载均衡策略 Rule</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">Ribbon 的负载均衡策略和之前讲过的负载均衡策略有部分相同,先来个全面的图,看下 Ribbon 有哪几种负载均衡策略。</p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.7289940828402367" data-s="300,640" src="/upload/8e858feaef7c498b8d6f4d3f40bcebec.png" data-type="png" data-w="845" style=""></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">再来看下 Ribbon 源码中关于均衡策略的 UML 类图。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.3392029657089898" src="/upload/c23d9cd2ad63a70592fc6caa1b49fdf1.png" data-type="png" data-w="1079" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> 负载均衡策略 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">由图可以看到,主要由以下几种均衡策略:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">线性轮询均衡</span> (RoundRobinRule):轮流依次请求不同的服务器。优点是无需记录当前所有连接的状态,无状态调度。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">可用服务过滤负载均衡</span>(AvailabilityFilteringRule):过滤多次访问故障而处于断路器状态的服务,还有过滤并发连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问。默认情况下,如果最近三次连接均失败,则认为该服务实例断路。然后保持 30s 后进入回路关闭状态,如果此时仍然连接失败,那么等待进入关闭状态的时间会随着失败次数的增加呈指数级增长。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">加权响应时间负载均衡</span>(WeightedResponseTimeRule):为每个服务按响应时长自动分配权重,响应时间越长,权重越低,被选中的概率越低。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">区域感知负载均衡</span>(ZoneAvoidanceRule):更倾向于选择发出调用的服务所在的托管区域内的服务,降低延迟,节省成本。Spring Cloud Ribbon 中默认的策略。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">重试负载均衡</span>(RetryRule):通过轮询均衡策略选择一个服务器,如果请求失败或响应超时,可以选择重试当前服务节点,也可以选择其他节点。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">高可用均衡</span>(BestAvailableRule):忽略请求失败的服务器,尽量找并发比较低的服务器。注意:这种会给服务器集群带来成倍的压力。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">随机负载均衡</span>(RandomRule):随机选择服务器。适合并发比较大的场景。 </section></li> </ul> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">四、 Ribbon 拦截请求的原理</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">本文最开始提出了一个问题:负载均衡器如何将客户端请求进行拦截然后选择服务器进行转发?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">结合上面介绍的 Ribbon 核心组件,我们可以画一张原理图来梳理下 Ribbon 拦截请求的原理:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="1.0763358778625953" src="/upload/678ae630e4f86214469f7b6e53e4cfbf.png" data-type="png" data-w="655" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">第一步:Ribbon 拦截所有标注<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@loadBalance</code>注解的 RestTemplate。RestTemplate 是用来发送 HTTP 请求的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">第二步:将 Ribbon 默认的拦截器 LoadBalancerInterceptor 添加到 RestTemplate 的执行逻辑中,当 RestTemplate 每次发送 HTTP 请求时,都会被 Ribbon 拦截。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">第三步:拦截后,Ribbon 会创建一个 ILoadBalancer 实例。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">第四步:ILoadBalancer 实例会使用 RibbonClientConfiguration 完成自动配置。就会配置好 IRule,IPing,ServerList。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">第五步:Ribbon 会从服务列表中选择一个服务,将请求转发给这个服务。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">五、Ribbon 初始化的原理</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">当我们去剖析 Ribbon 源码的时候,需要找到一个突破口,而 @LoadBalanced 注解就是一个比较好的入口。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">先来一张 Ribbon 初始化的流程图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="1.3435897435897435" src="/upload/622f2148ca77f54a618be80a4100869f.png" data-type="png" data-w="780" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> Ribbon 初始化过程 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">添加注解的代码如下所示:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/ibKHP1TZZeXJcMdxaKL5xItgg4QQt7b6TrXvwvGZVOUzZfGThXHLKmg1Tk37EWJF4iaibZic9lRo9wNWVvUBrHTb1f16Vjuwzp4w/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #383a42;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fafafa;border-radius: 5px;"><span style="color: #4078f2;line-height: 26px;">@LoadBalanced</span><br><span style="color: #4078f2;line-height: 26px;">@Bean</span><br><span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;RestTemplate&nbsp;<span style="color: #4078f2;line-height: 26px;">getRestTemplate</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;<span style="color: #a626a4;line-height: 26px;">return</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;RestTemplate();<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">第一步:Ribbon 有一个自动配置类 LoadBalancerAutoConfiguration,SpringBoot 加载自动配置类,就会去初始化 Ribbon。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">第二步:当我们给 RestTemplate 或者 AsyncRestTemplate 添加注解后,Ribbon 初始化时会收集加了 @LoadBalanced 注解的 RestTemplate 和 AsyncRestTemplate ,把它们放到一个 List 里面。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">第三步:然后 Ribbon 里面的 RestTemplateCustomizer 会给每个 RestTemplate 进行定制化,也就是加上了拦截器:LoadBalancerInterceptor。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">第四步:从 Eureka 注册中心获取服务列表,然后存到 Ribbon 中。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">第五步:加载 YMAL 配置文件,配置好负载均衡配置,创建一个 ILoadbalancer 实例。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">六、Ribbon 同步服务列表原理</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">Ribbon 首次从 Eureka 获取全量注册表后,就会隔一定时间获取注册表。原理图如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="1.5328767123287672" src="/upload/d1e532c991db67cb179543b99aee304f.png" data-type="png" data-w="730" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> Ribbon 同步服务列表的原理图 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">之前我们提到过 Ribbon 的核心组件 ServerListUpdater,用来同步注册表的,它有一个实现类 PollingServerListUpdater ,专门用来做定时同步的。默认1s 后执行一个 Runnable 线程,后面就是每隔 30s 执行 Runnable 线程。这个 Runnable 线程就是去获取 Eureka 注册表的。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">七、Eureka 心跳检测的原理</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">我们知道 Eureka 注册中心是通过心跳检测机制来判断服务是否可用的,如果不可用,可能会把这个服务摘除。为什么是可能呢?因为 Eureka 有自我保护机制,如果达到自我保护机制的阀值,后续就不会自动摘除。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">这里我们可以再复习下 Eureka 的自我保护机制和服务摘除机制。</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;font-size: 15px;"><span style="font-weight: 700;color: rgb(248, 57, 41);">Eureka 心跳机制</span>:每个服务每隔 30s 自动向 Eureka Server 发送一次心跳,Eureka Server 更新这个服务的最后心跳时间。如果 180 s 内(版本1.7.2)未收到心跳,则任务服务故障了。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;font-size: 15px;"><span style="font-weight: 700;color: rgb(248, 57, 41);">Eureka 自我保护机制</span>:如果上一分钟实际的心跳次数,比我们期望的心跳次数要小,就会触发自我保护机制,不会摘除任何实例。期望的心跳次数:服务实例数量 * 2 * 0.85。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;font-size: 15px;"><span style="font-weight: 700;color: rgb(248, 57, 41);">Eureka 服务摘除机制</span>:不是一次性将服务实例摘除,每次最多随机摘除 15%。如果摘除不完,1 分钟之后再摘除。</p> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">说完 Eureka 的心跳机制和服务摘除机制后,我们来看下 Ribbon 的心跳机制。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">八、Ribbon 心跳检测的原理</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">Ribbon 的心跳检测原理和 Eureka 还不一样,<span style="font-weight: 700;color: rgb(248, 57, 41);">Ribbon 不是通过每个服务向 Ribbon 发送心跳或者 Ribbon 给每个服务发送心跳来检测服务是否存活的</span>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">先来一张图看下 Ribbon 的心跳检测机制:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="1.0530474040632054" src="/upload/8a4f955ce783234e9ee3c543b908e730.png" data-type="png" data-w="886" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> Ribbon 心跳检测的原理 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">Ribbon 心跳检测原理:对自己本地缓存的 Server List 进行遍历,看下每个服务的状态是不是 UP 的。具体的代码就是 isAlive 方法。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">核心代码:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/ibKHP1TZZeXJcMdxaKL5xItgg4QQt7b6TrXvwvGZVOUzZfGThXHLKmg1Tk37EWJF4iaibZic9lRo9wNWVvUBrHTb1f16Vjuwzp4w/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #383a42;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fafafa;border-radius: 5px;">isAlive&nbsp;=&nbsp;status.equals(InstanceStatus.UP);<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">那么多久检测一次呢?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">默认每隔<span style="color: rgb(255, 104, 39);"> 30s</span> 执行以下 PingTask 调度任务,对每个服务执行 isAlive 方法,判断下状态。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">九、Ribbon 常用配置项</span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">9.1 禁用 Eureka</span><span style="display: none;"></span></h3> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/ibKHP1TZZeXJcMdxaKL5xItgg4QQt7b6TrXvwvGZVOUzZfGThXHLKmg1Tk37EWJF4iaibZic9lRo9wNWVvUBrHTb1f16Vjuwzp4w/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #383a42;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fafafa;border-radius: 5px;"># 禁用 Eureka<br>ribbon.eureka.enabled=false<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">服务注册列表默认是从 Eureka 获取到的,如果不想使用 Eureka,可以禁用掉。然后我们需要手动配置服务列表。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">9.2 配置服务列表</span><span style="display: none;"></span></h3> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/ibKHP1TZZeXJcMdxaKL5xItgg4QQt7b6TrXvwvGZVOUzZfGThXHLKmg1Tk37EWJF4iaibZic9lRo9wNWVvUBrHTb1f16Vjuwzp4w/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #383a42;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fafafa;border-radius: 5px;">ribbon-config-passjava.ribbon.listOfServers=localhost:8081,localhost:8083<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">这个配置是针对具体服务的,前缀就是服务名称,配置完之后就可以和之前一样使用服务名称来调用接口了。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">9.3 其他配置项</span><span style="display: none;"></span></h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.2975206611570248" src="/upload/2032e7b58f7537922d6600ebb4c2e069.png" data-type="png" data-w="1089" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">十、总结</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">本篇深入讲解了 Spring Cloud 微服务中 负载均衡组件 Ribbon 架构原理,分为几大块:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Ribbon 的六大核心组件 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Ribbon 如何拦截请求并进行转发的。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Ribbon 初始化的原理。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Ribbon 如何同步 Eureka 注册表的原理。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Eureka 和 Ribbon 两种 心跳检测的原理 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Ribbon 的常用配置项。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">https://www.cnblogs.com/zhixiang-org-cn/archive/2019/10/31/11769320.html</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">https://my.oschina.net/u/3748584/blog/4814474</p> </section> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;white-space: normal;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;text-align: left;"></figure>

终于有人把OAuth2.0原理讲明白了!

作者:微信小助手

<section style="box-sizing: border-box;font-size: 16px;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="padding-top: 10px;padding-right: 10px;padding-left: 10px;background-color: rgb(239, 239, 239);box-sizing: border-box;"> <span style="display: inline-block;width: 5%;line-height: 0.8;font-weight: bolder;font-size: 48px;box-sizing: border-box;" title="" opera-tn-ra-cell="_$.pages:0.layers:0.comps:0.txt1"> <section style="box-sizing: border-box;"> “ </section></span> <section style="display: inline-block;vertical-align: top;float: right;width: 90%;line-height: 1.5;font-size: 15px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><span style="letter-spacing: 1px;">在互联网蓬勃发展的今天,互联网应用层出不穷,每个应用专注的领域和方法也不相同。</span></p> </section> <section style="clear: both;box-sizing: border-box;"> <section> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> </section> </section> </section> <section style="line-height: normal;"> <br> </section> <section style="text-align: center;margin-left: 8px;margin-right: 8px;"> <img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.6886160714285714" data-s="300,640" src="/upload/923368a4ece7a060324601f6e60048f5.png" data-type="png" data-w="896" style=""> </section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;letter-spacing: 1px;color: rgb(89, 89, 89);"><em>图片来自 Pexels</em></span><br></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">为了给用户更好的使用体验,一个互联网应用会请求用户授权获取另外一个应用,在获取授权之后就可以获取其他应用的资源,从而更好的为用户服务。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">OAuth 2.0 就是帮助用户新型第三方应用授权的协议,今天会给大家介绍 OAuth 2.0 的实现原理和协议授权规范。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">包括如下内容:</span></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li style="font-weight: bold;"><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;">从简单的例子了解 OAuth</span></strong></p></li> <li style="font-weight: bold;"><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;">OAuth&nbsp;2.0 的定义和组成</span></strong></p></li> <li style="font-weight: bold;"><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;">OAuth&nbsp;2.0 的 Refresh&nbsp;Token</span></strong></p></li> <li style="font-weight: bold;"><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;">OAuth&nbsp;2.0 的授权模式</span></strong></p></li> </ul> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="border-bottom: 1px solid black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;border-bottom: 6px solid rgb(89, 89, 89);margin-bottom: -1px;border-top-color: rgb(89, 89, 89);border-right-color: rgb(89, 89, 89);border-left-color: rgb(89, 89, 89);font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">从简单的例子了解 OAuth</p> </section> </section> </section> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在介绍 OAuth 2.0 之前,让我们来看一个简单的例子。假设你平时喜欢照相,将生活中的点点滴滴记录成电子照片并且存放到云盘上,每隔一段时间会将心仪的照片挑选出来进行打印保存。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">同时你发现网络上面有一个款云打印照片的应用,只需要导入电子照片,这款应用就可以帮你进行打印然后将成片邮寄到你的家中。</span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我们将这个例子中的授权部分抽离出来形成图 1 ,如图 1 所示,左边是云打印的部分,也就是我们需要使用的互联网服务。右边绿色的部分是用户,也就是电子照片的资源拥有者。</span> </section> <section style="text-align: center;line-height: 1.75em;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"> <img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.9117647058823529" data-s="300,640" src="/upload/fe2ad4b0119a7cce79b545e5c52b5ecf.png" data-type="png" data-w="748" style=""> </section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">图 1:云打印服务的授权过程</span></em></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">针对云盘而言有两个服务需要提供,一个是授权服务,也就是通过照片的所有者授权第三方应用使用照片资源,另一个就是资源服务本身,也就是照片资源的提供者。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">通过图 1 的展示我们将整个请求云打印服务和授权的过程分为如下几个步骤:</span></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">用户请求云打印服务,此时运用只是单纯地请求服务,但是并没有提供电子照片的资源给云打印服务。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">云打印服务接收到请求以后,由于没有电子照片云盘的访问权限,于是请求用户对云盘进行授权。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">用户为了实现云打印服务,随之授权云打印去访问云盘中的电子照片。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">云打印将用户的授权告诉云盘中的授权服务。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">授权服务得知用户授权云打印服务可以打印用户在云盘中的照片时,返回给云打印服务访问权限。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">拿到访问照片资源权限的云打印服务,利用该访问权限访问云盘上面的电子照片资源。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">云盘上的资源服务接收到待访问权限的请求之后,返回电子照片,随后云打印服务开始打印服务。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="border-bottom: 1px solid black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;border-bottom: 6px solid rgb(89, 89, 89);margin-bottom: -1px;border-top-color: rgb(89, 89, 89);border-right-color: rgb(89, 89, 89);border-left-color: rgb(89, 89, 89);font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">OAuth&nbsp;2.0 的定义和组成</p> </section> </section> </section> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">从上面这个小例子可以发现当用户访问第三方的网络应用(云打印)的时候,需要通过授权的方式让云打印具备访问云盘资源的权限。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">授权过后云盘的授权服务会返回给云打印应有的权限,注意这里并没有返回给云打印所有云盘权限。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">例如:添加、删除、修改电子照片,只是根据用户的授权给了云打印部分的权限,也就是获取电子照片的权限。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">为什么要经过这个授权的过程能,可以对其做如下分析:</span></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如果为了打印照片,用户将访问云盘的用户名密码都交给云打印服务显然不太安全。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">云打印在获得用户云盘授权的时候并不是获取所有的权限,而是获取部分权限,这个权限只是能够访问电子照片而已,而且通常而言还可以设置该权限的访问时长,例如:2 小时或者 1 天,从而保证打印服务的正常进行。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如果此时云打印通过得知用户名和密码的方式访问云盘,那么云打印的系统被黑,就会导致云盘的资源被泄漏。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">鉴于上面三点的分析,我们需要使用 OAuth 的方式进行授权。OAuth 认证是为了做到第三方应用在未获取到用户敏感信息(如:账号密码、用户 PIN 等)的情况下,能让用户授权予它来访问开放平台中的资源接口。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;">之所以使用 OAuth 2.0,是因为 OAuth 1.0 协议太复杂、易用性差较难普及。OAuth 2.0 通过新的协议设计,使用更加简单,更加容易普及。&nbsp;</span></p> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在对 OAuth 2.0 协议的设计目的了解之后,再来看看它的组成部分。把上面一节中提到的例子进行映射可以将其分为 4 个组成部分。</span> </section> <section style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.8086734693877551" data-s="300,640" src="/upload/45eb5700e987b9f66140a771cb615119.png" data-type="png" data-w="784" style=""> </section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">图 2:OAuth 2.0 执行流程</span></em></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">如图 2 所示:</span></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Client:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">作为访问应用的客户端,也就是需要经过授权才能访问资源的应用程序,在例子中就是第三方应用(云打印)。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Resource Owner:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">即资源所有者,例子中的用户,他可以授予第三方应用(云打印)也就是 Client,对受保护资源的访问权限的实体。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><strong>Authorization Server:</strong>即授权服务器,其作用是在 Resource Owner 验证并给予 Client 授权后,通过 Authorization Server 向 Client 颁发访问的令牌。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Resource Server:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">即资源服务器,它是用来存放资源的,在例子中用来存放电子照片,当 Client 使用令牌访问它的时候,它会接受响应并返回 Resource Owner 所保护的资源,也就是电子照片。</span></p></li> </ul> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">其中 Authorization Server 和 Resource Server 可以分开,也可能存在同一个服务器上面。按照上面的例子,这两部分都属于云盘服务器。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">上面介绍了 OAuth 2.0 的几个组件,这里再将图 2 中的执行流程给大家进行讲解:</span></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">客户端(Client)向资源所有者(Resource Owner)请求授权。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">客户端(Client)收到用户授权,这是代表资源所有者(Resource Owner)授权的凭证(Authorization)。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">客户端(Client)通过与授权服务器(Authorization Server)进行身份验证并提供授权许可来请求访问令牌(Access Token)。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">授权服务器(Authorization Server)对客户端进行身份验证并验证授权许可,如果有效,则颁发访问令牌(Access Token)。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">客户端(Client)从资源服务器(Resource Server)请求受保护的资源并通过提供访问令牌(Access Token)进行身份验证。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">资源服务器(Resource Server)验证访问令牌(Access Token),如果有效,则为请求提供服务。</span></p></li> </ul> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">通过上面的流程 Client 终于可以拿到 Resource Server 上的资源为 Resource Owner 提供对应的服务了。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这整个过程称为授权许可,它代表资源的凭证所有者(Resource Owner)授权给客户端(Client)访问其受保护的资源,以及客户端获取访问令牌的整个过程。</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="border-bottom: 1px solid black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;border-bottom: 6px solid rgb(89, 89, 89);margin-bottom: -1px;border-top-color: rgb(89, 89, 89);border-right-color: rgb(89, 89, 89);border-left-color: rgb(89, 89, 89);font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">OAuth&nbsp;2.0 的 Refresh&nbsp;Token</p> </section> </section> </section> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">上面说道资源服务器(Resource Server)是通过验证客户端(Client)的访问令牌(Access Token)来提供资源服务的,因此访问令牌(Access Token)就是访问受保护资源的凭据。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;">它是一个字符串,并由授权服务器(Authorization Server)颁发客户端(Client)的,同时会指定资源访问范围和持续时间。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">正因为如此访问令牌(Access Token)在超出范围,特别是超出访问时间的时候会出现失效的情况,此时客户端就需要获得额外的访问令牌(Access Token)。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;">此时授权服务器会给客户端发出刷新令牌(Refresh Token),与访问令牌(Access Token)不同的是刷新令牌(Refresh Token)仅用于授权服务器,从不发送 &nbsp;&nbsp;到资源服务器。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;">在后面会提到的授权码模式中,授权服务器会同时返回刷新令牌(Refresh Token)。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;">其目的是在访问令牌( Access Token)过期前,重新获取新的访问令牌(Access Token),不需要资源所有者(Resource Owner)重新确认授权,提高了授权效率和用户体验。</span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在访问令牌( Access Token) 前, 客户端(Client)可用刷新令牌(Refresh Token)向授权服务器(Authorization Server)发送请求。</span> </section> <section style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.4334470989761092" data-s="300,640" src="/upload/82daeaa40e135dd0c103fe5b1c737d10.png" data-type="png" data-w="586" style=""> </section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">图 3</span></em></span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如图 3 所示,假设 b.com 是授权服务器(Authorization Server)地址,</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">请求包含如下内容:</span></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">收到 grant_type:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">授权类型,值为 ‘refresh_token’。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">client_id:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">客户端 id,即客户端(Client)在授权服务器上注册被分配的 id。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">client_secret:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">客户端(Client)和授权服务器(Authorization Server)通行的密钥,由授权服务器颁发,在特殊需要确认的情况下需要作为验证条件。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">refresh_token:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">用户获取新的 access_token 的 refresh_token。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="border-bottom: 1px solid black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;border-bottom: 6px solid rgb(89, 89, 89);margin-bottom: -1px;border-top-color: rgb(89, 89, 89);border-right-color: rgb(89, 89, 89);border-left-color: rgb(89, 89, 89);font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">OAuth&nbsp;2.0 的授权模式</p> </section> </section> </section> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">前面给大家介绍了 OAuth 2.0 的定义和组成结构,并且详细描述了其授权的流程,并且提出了 Access Token 过期情况下 Refresh Token 的解决方案。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">接下来介绍 OAuth 2.0 的授权模式,也就是资源所有者将资源的使用权限授予给客户端的方式。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">这里列举 4 种授权模式,分别是:</span></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li style="font-weight: bold;"><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">授权码模式</span></strong></p></li> <li style="font-weight: bold;"><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">隐含授权模式</span></strong></p></li> <li style="font-weight: bold;"><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">密码模式</span></strong></p></li> <li style="font-weight: bold;"><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">客户端模式</span></strong></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">①授权码模式(Authorization Code)</span></strong></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">它是功能最完整、流程最严密的授权模式,其特点就是通过客户端的后台服务器,与"服务提供商"的认证服务器进行互动。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">授权码模式会使用两种访问权限令牌(Access Token)和刷新令牌(Refresh Token),授权过程基于重定向的流。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">客户端(Client)能够从资源所有者(Resource Owner)的用户代理(User Agent)接收传入的请求。</span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">然后通过重定 URI 发送给授权服务器(Authorization Server),并获取返回的访问令牌(Access Token)。&nbsp;</span> </section> <section style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.7719821162444114" data-s="300,640" src="/upload/a6c54d83d8589bb0cf1d331eedce56f5.png" data-type="png" data-w="671" style=""> </section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">图 4:授权码模式流程图</span></em></span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">如图 4 所示,这里将授权码模式的流程处理分为 5 个步骤:</span></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">客户端(Client)初始化流程,将资源所有者对应的用户代理(User Agent 浏览器)指向授权服务器(Authorization Server)。</span></p><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">此时客户端(Client)包含了本身的 ID、请求范围、本地状态以及重定向的URI的信息。这个 URI 是告诉授权服务器(Authorization Server)在授权完成之后回调用户代理的 URI。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">用户代理(User Agent)会发送给授权服务器(Authorization Server)用户的身份信息。</span></p><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">授权服务器(Authorization Server)会对资源所有者(Resource Owner)的身份进行认证,然后返回是否授权的结果。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">假设授权服务器(Authorization Server)通过了资源所有者的授权,它将授权码(Authorization Code)以及一些状态信息通过重定向URI通过用户代理返回给客户端(Client)。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">客户端收到授权码(Authorization Code),附上重定向的URI向授权服务器(Authorization Server)申请访问令牌(Access Token)。</span></p><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">同时也会附上重定向的 URI,当返回访问令牌(Access Token)的时候能够找到对应的客户端(Client)。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">认证服务器(Authorization Server)核对了授权码(Authorization Code)确认无误后,通过重定向的URI向客户端发送访问令牌(Access Token)和更新令牌(Refresh Token)。</span></p><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">后面的过程就是客户端使用访问令牌(Access Token)访问资源服务器(Resource Server)了。</span></p></li> </ul> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">通过上面对授权码模式的介绍,我们不仅会提出一个问题,客户端为什么要获取授权服务器中的授权吗?</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">再用这个授权码向授权服务器申请获取访问令牌,授权服务器直接把访问令牌发给客户端不久完了吗,非要绕着么大一圈不是多次一举吗?</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这里对这一原因进行解释如下:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">用户代理在显示中都以浏览器的方式存在,而浏览器中对应的重定向 URI(redirect_uri)被认为是不安全信道,此方式不适合敏感数据-访问令牌的传输。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">因为 URI 有可能通过 HTTP referrer 传递到其它恶意站点,也可能存在于浏览器 cacher 或 log 文件中,这就给攻击者盗取访问令牌提供了便利。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这里还有一个假设,就是设资源所有者的行为虽然是可信赖的,但是资源所有者所使用的用户代理,也就是浏览器可能早已被攻击者植入了跨站脚本用来监听访问令牌。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">此时将访问令牌用户代理传递给客户端,会扩大访问令牌被泄露的风险。但授权码(Authorization Code)是可以通过重定向 URI 来传递的。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">授权码并不像访问令牌那样敏感,即使授权码泄露了,攻击者也无法直接拿到访问令牌从而访问资源。因为拿到授权码去交换访问令牌时是需要验证客户端真实身份的。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">说白了就是除了客户端之外,其他人拿授权码事没有用的。这也事为什么访问令牌只能发给客户端使用的原因,其他任何主体包括资源所有者都不应该获取访问令牌。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">协议的设计保证客户端是唯一有能力获取访问令牌的主体。引入授权码的目的也是为了保证客户端是访问令牌的唯一持有人。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">另外,由于协议需要验证客户端的身份,如果不引入授权码,客户端的身份认证只能通过重定向 URI 来传递。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">由于重定向 URI 是一个不安全信道,就额外要求客户端必须使用数字签名技术来进行身份认证,而不能用简单的密码或口令认证方式。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">引入授权码之后,授权服务器可以直接对客户端进行身份认证,可以支持任意的客户端认证方式。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">可以理解为授权码作为客户端和资源所有者之间的中介,用来验证客户端的身份。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">②隐式授权模式(Implicit Grant )</span></strong></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">它是一种简化模式,由于前面一种模式需要通过授权码换取访问令牌的方式实现授权,在提升安全性的同时增加了复杂度。</span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">因此隐式授权模式会直接在用户代理(浏览器)中向授权服务器申请访问令牌,跳过了授权码这个步骤,所有步骤在浏览器中完成,访问令牌对访问者是可见的,且客户端不需要认证。</span> </section> <p style="text-align: center;line-height: 1.75em;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.9942028985507246" data-s="300,640" src="/upload/de407ec1b505bfec5a067e3cd1dd3009.png" data-type="png" data-w="690" style=""></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">图 5:隐式授权模式流程图</span></em></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">如图 5 所示,我们一起来看看隐式授权模式的执行流程:</span></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">客户端(Client)初始化流程,将资源所有者对应的用户代理(User Agent 浏览器)指向授权服务器(Authorization Server)。</span></p><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">此时客户端(Client)包含了本身的 ID、请求范围、本地状态以及重定向的URI的信息。这个 URI 是告诉授权服务器(Authorization Server)在授权完成之后回调用户代理的 URI。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">用户代理(User Agent)会发送给授权服务器(Authorization Server)用户的身份信息,授权服务器(Authorization Server)会对资源所有者(Resource Owner)的身份进行认证,然后返回是否授权的结果。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">假设授权服务器(Authorization Server)通过了资源所有者的授权,它将访问令牌(访问令牌)使用重定向 URI 通过用户代理返回给客户端(Client)。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">用户代理(User Agent)通过重定向的 URI 被指向到 Web 所托管的客户端资源上。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Web 所托管的客户端资源会返回一个 Web 页面,该页面是一个带有 Script 脚本的 HTML 文档,其中包含可以访问所有资源的访问令牌(Access Token)。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">用户代理(User Agent)也就是浏览器,在接收到返回的 Script 以后,从中抽取需要的访问令牌(Access Token)。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">随后用户代理(User Agent)将访问令牌(Access Token)传给客户端(Client),继续后续的资源获取工作。</span></p></li> </ul> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">正如前面提到的隐式授权模式简化了授权码获取的过程,通过 Web 托管客户资源返回的 Script 脚本中携带了对应的访问码,用户代理在抽取访问码之后返回给客户端调用资源。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这种方式虽然省去了获取授权码的过程,但是在用户代理中存放了访问码存在一定的安全风险。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">③密码模式(Resource Owner Password Credentials Grant)</span></strong></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">用户向客户端提供自己的用户名和密码。客户端使用这些信息,向授权服务器索要授权。在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。</span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这通常用在用户对客户端高度信任的前提下才能进行,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。</span> </section> <p style="text-align: center;line-height: 1.75em;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5081240768094535" data-s="300,640" src="/upload/22848a31afe2abf90fd627f395fbeb1a.png" data-type="png" data-w="677" style=""></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">图 6:密码模式流程图</span></em></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">接下来我们一起看看密码模式的执行流程,如图 6 所示,</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">整个过程比较简单分为 3 个步骤:</span></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">资源所有者向客户端提供用户名和密码</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">客户端将从资源所有者处获取的授权(用户名+密码)发送给授权服务器,从而获取访问资源服务器的权限。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">授权服务器确认资源所有者的授权(用户名+密码)之后返回访问令牌以及刷新令牌。</span></p></li> </ul> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">④客户端模式(Client Credentials Grant)</span></strong></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">指客户端以自己的名义,而不是以用户的名义,向授权服务器进行认证。在这种模式中,用户直接向客户端注册,客户端以自己的名义要求授权服务器提供服务,不存在授权问题。</span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">由于不存在资源所有者的授权行为,因此这种模式严格上来说不属于 OAuth 2.0 的模式范畴。客户端在授权服务器上存在可控资源的情况,才能使用这种方式。</span> </section> <section style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.16957026713124274" data-s="300,640" src="/upload/c3a83f399746acd235f2ebb73abbaaf5.png" data-type="png" data-w="861" style=""> </section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">图 7:客户端模式流程图</span></em></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">如图 7 所示,这种模式分为 2 步:</span></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">客户端自身向授权服务器发起授权请求,申请获取访问令牌。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">授权服务器在经过认证授权以后发送给客户端访问令牌。</span></p></li> </ul> <section style="line-height: normal;"> <br> </section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="border-bottom: 1px solid black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;border-bottom: 6px solid rgb(89, 89, 89);margin-bottom: -1px;border-top-color: rgb(89, 89, 89);border-right-color: rgb(89, 89, 89);border-left-color: rgb(89, 89, 89);font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">总结</p> </section> </section> </section> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">本文从云打印照片的例子开始,通过用户授权云打印服务访问云盘获取电子照片的整个过程,带出了 OAuth 2.0 所实现的资源授权与访问的功能。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">然后提出 OAuth 2.0 是用来保证第三方应用授权访问资源安全性的协议,其协议会涉及到客户端、资源所有者、授权服务器和资源服务器,并且描述了授权过程如何在它们之间展开的。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在介绍完授权流程之后,又进一步说明了在过程中获取访问令牌才能访问资源,如果令牌过期的情况下需要通过刷新令牌保持授权的有效性。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">最后介绍了 OAuth 2.0 的 4 种授权模式,分别是授权码模式、隐含授权模式、密码模式和客户端模式,以及它们的实现流程。</span></p> <section style="line-height: normal;"> <br> </section> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: center;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">👇</span></strong><span style="outline: 0px;max-width: 100%;letter-spacing: 0.544px;color: rgb(255, 41, 65);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">点击</span></strong></span><strong style="outline: 0px;max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">关注鸿蒙技术社区👇</span></strong></p> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzkzNzE0MTA4OQ==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/bmc8z80Q8fBthvCfLJkGNShxCDvq8LOYEMQrA17PgpwoLtF94tIRLVTnEDfAc7yIOLgJNUvDCmPSNmHQpnsCPw/0?wx_fmt=png" data-nickname="鸿蒙技术社区" data-alias="" data-signature="HarmonyOS(鸿蒙)技术社区是由51CTO和华为共同打造的综合性开发和应用技术社区。" data-from="0"></mpprofile> </section> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: center;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="letter-spacing: 0.544px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">了解</span></strong><span style="letter-spacing: 0.544px;outline: 0px;max-width: 100%;color: rgb(255, 41, 65);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">鸿蒙</span></strong></span><strong style="letter-spacing: 0.544px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">一手资讯</span></strong><br></p> <section style="white-space: normal;line-height: normal;"> <em style="color: rgb(89, 89, 89);letter-spacing: 1px;line-height: 1.75em;"><span style="font-size: 14px;">作者:崔皓</span></em> <br> </section> <p style="white-space: normal;line-height: 1.75em;"><span style="color: rgb(89, 89, 89);letter-spacing: 1px;"><em><span style="font-size: 14px;">简介:十六年开发和架构经验,曾担任过惠普武汉交付中心技术专家,需求分析师,项目经理,后在创业公司担任技术/产品经理。善于学习,乐于分享。目前专注于技术架构与研发管理。</span></em></span></p> <p style="white-space: normal;line-height: 1.75em;"><span style="color: rgb(89, 89, 89);letter-spacing: 1px;"><em><span style="font-size: 14px;">编辑:陶家龙</span></em></span><br></p> <p style="white-space: normal;"><span style="font-size: 14px;letter-spacing: 1px;color: rgb(89, 89, 89);"><em>征稿:有投稿、寻求报道意向技术人请联络 editor@51cto.com</em></span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.3939393939393939" src="/upload/68aa3ae08d2acf7c5b3b2bcaeec8a13d.png" data-type="gif" data-w="660" style=""></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="margin-top: 0.5em;margin-bottom: 0.5em;box-sizing: border-box;" powered-by="xiumi.us"> <section style="font-size: 15px;border-style: solid;border-width: 0px 0px 1px;color: rgb(89, 89, 89);border-bottom-color: rgba(215, 215, 215, 0.96);box-sizing: border-box;"> <p style="box-sizing: border-box;"><span style="letter-spacing: 1px;"><strong>精彩文章推荐:</strong></span></p> </section> </section> </section> <section style="line-height: 2em;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&amp;mid=2655854757&amp;idx=2&amp;sn=1e97f40fac22443bf9cffcfbd2684b04&amp;chksm=bd756d728a02e4644b0406b679ce2e2724679b2a2d2328dc431f77e375af318ed16eecf1f41d&amp;scene=21#wechat_redirect" textvalue="面试官:谈谈Tomcat连接器,我一脸懵逼..." linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;" data-linktype="2"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">面试官:谈谈Tomcat连接器,我一脸懵逼...</span></a> <br> </section> <section style="line-height: 2em;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&amp;mid=2655854901&amp;idx=1&amp;sn=ec1993513583753dc8855770fb8160be&amp;chksm=bd756ce28a02e5f4df42be2b5ab1f1a528560f642c655dedca371339e8899f1e57b6acead586&amp;scene=21#wechat_redirect" textvalue="为什么苹果、谷歌、阿里做不出工业软件?" linktype="text" imgurl="" imgdata="null" data-itemshowtype="11" tab="innerlink" style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;" data-linktype="2"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">为什么苹果、谷歌、阿里做不出工业软件?</span></a> <br> </section> <section style="line-height: 2em;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&amp;mid=2655854604&amp;idx=1&amp;sn=65106304e5c3a4e6dc324a2768dd5dea&amp;chksm=bd756ddb8a02e4cd2903f1a93df8a33e568a5dfba6c472f7fc7a2418c6702a6fe60615435476&amp;scene=21#wechat_redirect" textvalue="不懂“元宇宙”,被鄙视了..." linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;" data-linktype="2"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">不懂“元宇宙”,被鄙视了...</span></a> <br> </section>

Spring18问,看你能对几题!

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;padding: 5px;font-size: 16px;color: rgb(53, 53, 53);word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">大家好,我是飘渺!今天整理了一下关于 spring 的面试题,网上也翻了翻关于 spring 的面试题,汇总了一下,基本都在这里了,当然可能有些过于基本的概念我是直接整理到某一问当中了,就没有单独再开设一问,祝大家面试顺利~</p> <hr data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;height: 1px;border-width: initial;border-style: none;border-color: initial;text-align: center;background-image: linear-gradient(to right, rgba(248, 57, 41, 0), rgba(248, 57, 41, 0.75), rgba(248, 57, 41, 0));"> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 1.spring 中都用到了哪些设计模式? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 2.spring 中有哪些核心模块? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 3.说一下你理解的 IOC 是什么? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 4.spring 中的 IOC 容器有哪些?有什么区别? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 5.那 BeanFactory 和 FactoryBean 又有什么区别? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 6.@Repository、@Service、@Compent、@Controller它们有什么区别? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 7.那么 DI 又是什么? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 8.说说 AOP 是什么? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 9.动态代理和静态代理有什么区别? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 10.JDK 动态代理和 CGLIB 代理有什么区别? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 11.Spring AOP 和 AspectJ AOP 有什么区别? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 12.spring 中 Bean 的生命周期是怎样的? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 13.spring 是怎么解决循环依赖的? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 14.为什么要使用三级缓存,二级缓存不能解决吗? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 15.@Autowired 和 @Resource 有什么区别? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 16.spring 事务隔离级别有哪些? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 17.spring 事务的传播机制有哪些? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 18.springBoot 自动装配原理? </section></li> </ul> <hr data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;height: 1px;border-width: initial;border-style: none;border-color: initial;text-align: center;background-image: linear-gradient(to right, rgba(248, 57, 41, 0), rgba(248, 57, 41, 0.75), rgba(248, 57, 41, 0));"> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">1.spring 中都用到了哪些设计模式?</span></h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.5364963503649635" src="/upload/c6de0df5b59f5d1914b44205524c2da6.png" data-type="other" data-w="822" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">1.工厂设计模式</span>: 比如通过 BeanFactory 和 ApplicationContext 来生产 Bean 对象</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">2.代理设计模式</span>: &nbsp;AOP 的实现方式就是通过代理来实现,Spring主要是使用 JDK 动态代理和 CGLIB 代理</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">3.单例设计模式</span>: Spring 中的 Bean 默认都是单例的</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">4.模板方法模式</span>: Spring 中 jdbcTemplate 等以 Template 结尾的对数据库操作的类,都会使用到模板方法设计模式,一些通用的功能</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">5.包装器设计模式</span>: 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">6.观察者模式:</span> Spring 事件驱动模型观察者模式的</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">7.适配器模式</span>:Spring AOP 的增强或通知(Advice)使用到了适配器模式</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">2.spring 中有哪些核心模块?</span></h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.7766714082503556" src="/upload/56e92e12a571014f716231800c0858df.png" data-type="other" data-w="703" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">1.<span style="font-weight: 700;color: rgb(248, 57, 41);">Spring Core</span>:Spring核心,它是框架最基础的部分,提供IOC和依赖注入DI特性</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">2.<span style="font-weight: 700;color: rgb(248, 57, 41);">Spring Context</span>:Spring上下文容器,它是 BeanFactory 功能加强的一个子接口</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">3.<span style="font-weight: 700;color: rgb(248, 57, 41);">Spring Web</span>:它提供Web应用开发的支持</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">4.<span style="font-weight: 700;color: rgb(248, 57, 41);">Spring MVC</span>:它针对Web应用中MVC思想的实现</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">5.<span style="font-weight: 700;color: rgb(248, 57, 41);">Spring DAO</span>:提供对JDBC抽象层,简化了JDBC编码,同时,编码更具有健壮性</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">6.<span style="font-weight: 700;color: rgb(248, 57, 41);">Spring ORM</span>:它支持用于流行的ORM框架的整合,比如:Spring + Hibernate、Spring + iBatis、Spring + JDO的整合等</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">7.<span style="font-weight: 700;color: rgb(248, 57, 41);">Spring AOP</span>:即面向切面编程,它提供了与AOP联盟兼容的编程实现</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><br></p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">3.说一下你理解的 IOC 是什么?</span></h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.8195121951219512" src="/upload/b03455ac1c805f376b086df9ee2069fc.png" data-type="other" data-w="410" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">首先 IOC 是一个<span style="font-weight: 700;color: rgb(248, 57, 41);">容器</span>,是用来装载对象的,它的核心思想就是 <span style="font-weight: 700;color: rgb(248, 57, 41);">控制反转</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">那么究竟<span style="font-weight: 700;color: rgb(248, 57, 41);">什么是控制反转</span> ?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">控制反转就是说,<span style="font-weight: 700;color: rgb(248, 57, 41);">把对象的控制权交给了 spring,由 spring 容器进行管理</span>,我们不进行任何操作</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">那么<span style="font-weight: 700;color: rgb(248, 57, 41);">为什么需要控制反转</span>?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">我们想象一下,没有控制反转的时候,我们需要 <span style="font-weight: 700;color: rgb(248, 57, 41);">自己去创建对象,配置对象</span>,还要 <span style="font-weight: 700;color: rgb(248, 57, 41);">人工去处理对象与对象之间的各种复杂的依赖关系</span>,当一个工程的量起来之后,这种关系的维护是非常令人头痛的,所以就有了控制反转这个概念,将对象的创建、配置等一系列操作交给 spring 去管理,我们在使用的时候只要去取就好了</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><br></p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">4.spring 中的 IOC 容器有哪些?有什么区别?</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">spring 主要提供了<span style="font-weight: 700;color: rgb(248, 57, 41);">两种 IOC 容器</span>,一种是 <span style="font-weight: 700;color: rgb(248, 57, 41);">BeanFactory</span>,还有一种是 <span style="font-weight: 700;color: rgb(248, 57, 41);">ApplicationContext</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">它们的区别就在于,BeanFactory <span style="font-weight: 700;color: rgb(248, 57, 41);">只提供了最基本的实例化对象和拿对象的功能</span>,而 ApplicationContext 是继承了 BeanFactory 所派生出来的产物,是其子类,它的作用更加的强大,比如支持注解注入、国际化等功能</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><br></p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">5.那 BeanFactory 和 FactoryBean 又有什么区别?</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这两个是<span style="font-weight: 700;color: rgb(248, 57, 41);">不同的产物</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">BeanFactory 是 IOC 容器</span>,是用来承载对象的</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">FactoryBean 是一个接口</span>,为 Bean 提供了更加灵活的方式,通过代理一个Bean对象,对方法前后做一些操作。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><br></p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">6.@Repository、@Service、@Compent、@Controller它们有什么区别?</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这四个注解的<span style="font-weight: 700;color: rgb(248, 57, 41);">本质都是一样的,都是将被该注解标识的对象放入 spring 容器当中,只是为了在使用上区分不同的应用分层</span></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> @Repository:dao层 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> @Service:service层 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> @Controller:controller层 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> @Compent:其他不属于以上三层的统一使用该注解 </section></li> </ul> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <br> </section> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">7.那么 DI 又是什么?</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">DI 就是依赖注入,其实和 IOC 大致相同,只不过是<span style="font-weight: 700;color: rgb(248, 57, 41);">同一个概念使用了不同的角度去阐述</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">DI 所描述的<span style="font-weight: 700;color: rgb(248, 57, 41);">重点是在于依赖</span> ,我们说了 <span style="font-weight: 700;color: rgb(248, 57, 41);">IOC 的核心功能就是在于在程序运行时动态的向某个对象提供其他的依赖对象</span>,而这个功能就是依靠 DI 去完成的,比如我们需要注入一个对象 A,而这个对象 A 依赖一个对象 B,那么我们就需要把这个对象 B 注入到对象 A 中,这就是依赖注入</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">spring 中有三种注入方式</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 接口注入 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 构造器注入 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> set注入 </section></li> </ul> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <br> </section> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">8.说说 AOP 是什么?</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">AOP 意为:<span style="font-weight: 700;color: rgb(248, 57, 41);">面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术</span>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">AOP 是 <span style="font-weight: 700;color: rgb(248, 57, 41);">OOP(面向对象编程) 的延续</span>,是 Spring 框架中的一个重要内容,是函数式编程的一种衍生范型。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">AOP 实现主要分为两类:</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.33603707995365006" src="/upload/6348394b9390b62c3fae71dc5f8757da.png" data-type="other" data-w="863" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">静态 AOP 实现</span>, AOP 框架 <span style="font-weight: 700;color: rgb(248, 57, 41);">在编译阶段</span> 对程序源代码进行修改,生成了静态的 AOP 代理类(生成的 *.class 文件已经被改掉了,需要使用特定的编译器),比如 AspectJ </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">动态 AOP 实现</span>, AOP 框架 <span style="font-weight: 700;color: rgb(248, 57, 41);">在运行阶段</span>对动态生成代理对象(在内存中以 JDK 动态代理,或 CGlib 动态地生成 AOP 代理类),如 SpringAOP </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">spring 中 AOP 的实现是<span style="font-weight: 700;color: rgb(248, 57, 41);">通过动态代理实现的</span>,如果是实现了接口就会使用 JDK 动态代理,否则就使用 CGLIB 代理。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><img class="rich_pages wxw-img" data-ratio="0.4599609375" src="/upload/7d011085682d81994ef62a76f142bf1a.png" data-type="png" data-w="1024"><span style="font-weight: 700;color: rgb(248, 57, 41);">有 5 种通知类型:</span></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">@Before</span>:在目标方法调用前去通知 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">@AfterReturning</span>:在目标方法返回或异常后调用 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">@AfterThrowing</span>:在目标方法返回后调用 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">@After</span>:在目标方法异常后调用 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">@Around</span>:将目标方法封装起来,自己确定调用时机 </section></li> </ul> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <br> </section> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">9.动态代理和静态代理有什么区别?</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">静态代理</span></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 静态代理通常只代理一个类 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 静态代理事先知道要代理的是什么 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">动态代理</span></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 在程序运行时,运用反射机制动态创建而成 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 动态代理是代理一个接口下的多个实现类 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 动态代理不知道要代理什么东西,只有在运行时才知道 </section></li> </ul> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <br> </section> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">10.JDK 动态代理和 CGLIB 代理有什么区别?</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">JDK 动态代理时业务类<span style="font-weight: 700;color: rgb(248, 57, 41);">必须要实现某个接口</span>,它是<span style="font-weight: 700;color: rgb(248, 57, 41);">基于反射的机制实现的</span>,生成一个实现同样接口的一个代理类,然后通过重写方法的方式,实现对代码的增强。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">CGLIB 动态代理是使用字节码处理框架 ASM,其原理是通过字节码技术为一个类<span style="font-weight: 700;color: rgb(248, 57, 41);">创建子类,然后重写父类的方法</span>,实现对代码的增强。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><br></p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">11.Spring AOP 和 AspectJ AOP 有什么区别?</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">Spring AOP 是运行时增强,是通过<span style="font-weight: 700;color: rgb(248, 57, 41);">动态代理实现</span>的</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="letter-spacing: 0.8px;word-spacing: 0.8px;">AspectJ AOP 是编译时增强,需要特殊的编译器才可以完成,是通过</span><span style="letter-spacing: 0.8px;word-spacing: 0.8px;font-weight: 700;color: rgb(248, 57, 41);">修改代码来实现</span><span style="letter-spacing: 0.8px;word-spacing: 0.8px;">的,支持</span><span style="letter-spacing: 0.8px;word-spacing: 0.8px;font-weight: 700;color: rgb(248, 57, 41);">三种织入方式</span><span style="color: rgb(248, 57, 41);font-weight: 700;letter-spacing: 0.8px;word-spacing: 0.8px;"></span></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">编译时织入</span>:就是在编译字节码的时候织入相关代理类 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">编译后织入</span>:编译完初始类后发现需要 AOP 增强,然后织入相关代码 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">类加载时织入</span>:指在加载器加载类的时候织入 </section></li> </ul> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <img class="rich_pages wxw-img" data-ratio="0.4097706879361914" src="/upload/ec42e7d9625cc3763f0e4247436b056b.png" data-type="png" data-w="1003" style="color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;white-space: normal;word-spacing: 0.8px;"> </section> <section data-tool="mdnice编辑器" style="overflow-x: auto;"> <table> <thead> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <th style="border-top-width: 1px;border-color: rgb(204, 204, 204);text-align: left;background-color: rgb(219, 217, 216);min-width: 85px;">主要区别</th> <th style="border-top-width: 1px;border-color: rgb(204, 204, 204);text-align: left;background-color: rgb(219, 217, 216);min-width: 85px;">Spring AOP</th> <th style="border-top-width: 1px;border-color: rgb(204, 204, 204);text-align: left;background-color: rgb(219, 217, 216);min-width: 85px;">AspecjtJ AOP</th> </tr> </thead> <tbody style="border-width: 0px;border-style: initial;border-color: initial;"> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <td style="border-color: rgb(204, 204, 204);color: rgb(100, 86, 71);min-width: 85px;">增强方式</td> <td style="border-color: rgb(204, 204, 204);color: rgb(100, 86, 71);min-width: 85px;">运行时增强</td> <td style="border-color: rgb(204, 204, 204);color: rgb(100, 86, 71);min-width: 85px;">编译时增强</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"> <td style="border-color: rgb(204, 204, 204);color: rgb(100, 86, 71);min-width: 85px;">实现方式</td> <td style="border-color: rgb(204, 204, 204);color: rgb(100, 86, 71);min-width: 85px;">动态代理</td> <td style="border-color: rgb(204, 204, 204);color: rgb(100, 86, 71);min-width: 85px;">修改代码</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <td style="border-color: rgb(204, 204, 204);color: rgb(100, 86, 71);min-width: 85px;">编译器</td> <td style="border-color: rgb(204, 204, 204);color: rgb(100, 86, 71);min-width: 85px;">javac</td> <td style="border-color: rgb(204, 204, 204);color: rgb(100, 86, 71);min-width: 85px;">特殊的编译器 ajc</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"> <td style="border-color: rgb(204, 204, 204);color: rgb(100, 86, 71);min-width: 85px;">效率</td> <td style="border-color: rgb(204, 204, 204);color: rgb(100, 86, 71);min-width: 85px;">较低(运行时反射损耗性能)</td> <td style="border-color: rgb(204, 204, 204);color: rgb(100, 86, 71);min-width: 85px;">较高</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <td style="border-color: rgb(204, 204, 204);color: rgb(100, 86, 71);min-width: 85px;">织入方式</td> <td style="border-color: rgb(204, 204, 204);color: rgb(100, 86, 71);min-width: 85px;">运行时</td> <td style="border-color: rgb(204, 204, 204);color: rgb(100, 86, 71);min-width: 85px;">编译时、编译后、类加载时</td> </tr> </tbody> </table> </section> <section data-tool="mdnice编辑器" style="overflow-x: auto;"> <br> </section> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">12.spring 中 Bean 的生命周期是怎样的?</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">SpringBean 生命周期大致分为4个阶段:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"></figure> <img class="rich_pages wxw-img" data-ratio="0.13703703703703704" src="/upload/393445d1847103ee72d86fe0654221ed.png" data-type="png" data-w="1080"> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">1.<span style="font-weight: 700;color: rgb(248, 57, 41);">实例化</span>,实例化该 Bean 对象</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">2.<span style="font-weight: 700;color: rgb(248, 57, 41);">填充属性</span>,给该 Bean 赋值</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">3.<span style="font-weight: 700;color: rgb(248, 57, 41);">初始化</span></p> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);list-style-type: square;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 如果实现了 Aware 接口,会通过其接口获取容器资源 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 如果实现了 BeanPostProcessor 接口,则会回调该接口的前置和后置处理增强 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 如果配置了 init-method 方法,]会执行该方法 </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">4.<span style="font-weight: 700;color: rgb(248, 57, 41);">销毁</span></p> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);list-style-type: square;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 如果实现了 DisposableBean 接口,则会回调该接口的 destroy 方法 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 如果配置了 destroy-method 方法,则会执行 destroy-method 配置的方法 </section></li> </ul> </ul> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <br> </section> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">13.spring 是怎么解决循环依赖的?</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><img class="rich_pages wxw-img" data-ratio="0.42045454545454547" src="/upload/b0264a1b03a782bb6fcfbc3c42f5bb80.png" data-type="other" data-w="528" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;">循环依赖就是说两个对象相互依赖,形成了一个环形的调用链路</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">spring 使用三级缓存去解决循环依赖的,其<span style="font-weight: 700;color: rgb(248, 57, 41);">核心逻辑就是把实例化和初始化的步骤分开,然后放入缓存中</span>,供另一个对象调用</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">第一级缓存</span>:用来保存实例化、初始化都完成的对象 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">第二级缓存</span>:用来保存实例化完成,但是未初始化完成的对象 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">第三级缓存</span>:用来保存一个对象工厂,提供一个匿名内部类,用于创建二级缓存中的对象 </section></li> </ul> <hr data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;height: 1px;border-width: initial;border-style: none;border-color: initial;text-align: center;background-image: linear-gradient(to right, rgba(248, 57, 41, 0), rgba(248, 57, 41, 0.75), rgba(248, 57, 41, 0));"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">当 A、B 两个类发生循环引用时 大致流程</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">1.A 完成实例化后,去<span style="font-weight: 700;color: rgb(248, 57, 41);">创建一个对象工厂,并放入三级缓存</span>当中</p> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);list-style-type: square;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 如果 A 被 AOP 代理,那么通过这个工厂获取到的就是 A 代理后的对象 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 如果 A 没有被 AOP 代理,那么这个工厂获取到的就是 A 实例化的对象 </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">2.A 进行属性注入时,去<span style="font-weight: 700;color: rgb(248, 57, 41);">创建 B</span></p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">3.B 进行属性注入,需要 A ,则<span style="font-weight: 700;color: rgb(248, 57, 41);">从三级缓存中去取 A 工厂代理对象</span>并注入,然后删除三级缓存中的 A 工厂,将 A 对象放入二级缓存</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">4.B 完成后续属性注入,直到初始化结束,将 B 放入一级缓存</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">5.<span style="font-weight: 700;color: rgb(248, 57, 41);">A 从一级缓存中取到 B 并且注入 B</span>, 直到完成后续操作,将 A 从二级缓存删除并且放入一级缓存,循环依赖结束</p> </section></li> </ul> <hr data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;height: 1px;border-width: initial;border-style: none;border-color: initial;text-align: center;background-image: linear-gradient(to right, rgba(248, 57, 41, 0), rgba(248, 57, 41, 0.75), rgba(248, 57, 41, 0));"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">spring 解决循环依赖有两个前提条件:</p> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 1. <span style="font-weight: 700;color: rgb(248, 57, 41);">不全是构造器方式</span>的循环依赖(否则无法分离初始化和实例化的操作) </section> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 2. <span style="font-weight: 700;color: rgb(248, 57, 41);">必须是单例</span>(否则无法保证是同一对象) </section> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <br> </section> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">14.为什么要使用三级缓存,二级缓存不能解决吗?</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">可以,三级缓存的功能是只有真正发生循环依赖的时候,才去提前生成代理对象,否则只会<span style="font-weight: 700;color: rgb(248, 57, 41);">创建一个工厂并将其放入到三级缓存</span>中,但是不会去通过这个工厂去真正创建对象。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">如果使用二级缓存解决循环依赖,意味着所有 Bean 在实例化后就要完成 AOP 代理,这样<span style="font-weight: 700;color: rgb(248, 57, 41);">违背了 Spring 设计的原则</span>,Spring 在设计之初就是在 Bean 生命周期的最后一步来完成 AOP 代理,而不是在实例化后就立马进行 AOP 代理。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">15.@Autowired 和 @Resource 有什么区别?</span></h2> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">@Resource 是 Java 自己的注解</span>,@Resource 有两个属性是比较重要的,分是 name 和 type;Spring 将 @Resource 注解的 name 属性解析为 bean 的名字,而 type 属性则解析为 bean 的类型。所以如果使用 name 属性,则使用 byName 的自动注入策略,而使用 type 属性时则使用 byType 自动注入策略。如果既不指定 name 也不指定 type 属性,这时将通过反射机制使用 byName 自动注入策略。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">@Autowired 是spring 的注解</span>,是 spring2.5 版本引入的,Autowired 只根据 type 进行注入,<span style="font-weight: 700;color: rgb(248, 57, 41);">不会去匹配 name</span>。如果涉及到 type 无法辨别注入对象时,那需要依赖 @Qualifier 或 @Primary 注解一起来修饰。</p> </section></li> </ul> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><br></p> </section> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">16.spring 事务隔离级别有哪些?</span></h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.42905788876276957" src="/upload/1084391017867311ef5c154cd7616668.png" data-type="other" data-w="881" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> DEFAULT:采用 DB 默认的事务隔离级别 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> READ_UNCOMMITTED:读未提交 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> READ_COMMITTED:读已提交 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> REPEATABLE_READ:可重复读 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> SERIALIZABLE:串行化 </section></li> </ul> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <br> </section> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">17.spring 事务的传播机制有哪些?</span></h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.5731843575418994" src="/upload/242ec5a615bd49f6f68b949075513154.png" data-type="other" data-w="895" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> <br> </figcaption> </figure> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">1.<span style="font-weight: 700;color: rgb(248, 57, 41);">propagation_required</span><br>当前方法<span style="font-weight: 700;color: rgb(248, 57, 41);">必须在一个具有事务的上下文中运行</span>,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。(如果被调用端发生异常,那么调用端和被调用端事务都将回滚)</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">2.<span style="font-weight: 700;color: rgb(248, 57, 41);">propagation_supports</span><br>当前方法不必需要具有一个事务上下文,但是如果有一个事务的话,它也可以在这个事务中运行</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">3.<span style="font-weight: 700;color: rgb(248, 57, 41);">propagation_mandatory</span><br>表示当前方法<span style="font-weight: 700;color: rgb(248, 57, 41);">必须在一个事务中运行</span>,如果没有事务,将抛出异常</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">4.<span style="font-weight: 700;color: rgb(248, 57, 41);">propagation_nested</span><br>如果当前方法正有一个事务在运行中,则该方法应该<span style="font-weight: 700;color: rgb(248, 57, 41);">运行在一个嵌套事务</span>中,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。如果封装事务不存在,则同propagation_required的一样</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">5.<span style="font-weight: 700;color: rgb(248, 57, 41);">propagation_never</span><br>当方法务不应该在一个事务中运行,如果<span style="font-weight: 700;color: rgb(248, 57, 41);">存在一个事务,则抛出异常</span></p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">6.<span style="font-weight: 700;color: rgb(248, 57, 41);">propagation_requires_new</span><br>当前方法<span style="font-weight: 700;color: rgb(248, 57, 41);">必须运行在它自己的事务中</span>。一个新的事务将启动,而且如果有一个现有的事务在运行的话,则这个方法将在运行期被挂起,直到新的事务提交或者回滚才恢复执行。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">7.<span style="font-weight: 700;color: rgb(248, 57, 41);">propagation_not_supported</span><br>方法不应该在一个事务中运行。<span style="font-weight: 700;color: rgb(248, 57, 41);">如果有一个事务正在运行,他将在运行期被挂起,直到这个事务提交或者回滚才恢复执行</span></p> </section></li> </ul> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);"><br></span></p> </section> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">18.springBoot 自动装配原理?</span></h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.9833333333333333" src="/upload/d29b38124a718fda20f5b8498fc29871.png" data-type="other" data-w="1080" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">1.容器在启动的时候会调用 EnableAutoConfigurationImportSelector.class 的 selectImports方法<span style="font-weight: 700;color: rgb(248, 57, 41);">获取一个全面的常用 BeanConfiguration 列表</span></p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">2.之后会读取 spring-boot-autoconfigure.jar 下面的spring.factories,<span style="font-weight: 700;color: rgb(248, 57, 41);">获取到所有的 Spring 相关的 Bean 的全限定名 ClassName</span></p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">3.之后继续<span style="font-weight: 700;color: rgb(248, 57, 41);">调用 filter 来一一筛选</span>,过滤掉一些我们不需要不符合条件的 Bean</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">4.最后把符合条件的 BeanConfiguration 注入默认的 EnableConfigurationPropertie 类里面的属性值,并且<span style="font-weight: 700;color: rgb(248, 57, 41);">注入到 IOC 环境当中</span></p> </section></li> </ul> </section> <p><br></p> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="Mzk0MjA4ODcxNQ==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/9dwzhvuGc8aTWJghDVm2VibCUovZ0s1PfXEMFvibo9MznUTdTvJzSmevPh3ciaE7BzPm8X6RMnFSbNeicS3uBy1qVA/0?wx_fmt=png" data-nickname="moon聊技术" data-alias="onetraveller_llxz" data-signature="玩玩技术,聊聊人生,看看生活,搞搞理想" data-from="0"></mpprofile> </section>

25种代码坏味道总结+优化示例,你中招没?

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;padding: 5px;font-size: 16px;color: rgb(53, 53, 53);word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">大家好,我是不才陈某~</span></p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">前言</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">什么样的代码是好代码呢?好的代码应该命名规范、可读性强、扩展性强、健壮性......而不好�

Kong 优雅实现微服务网关鉴权,登录场景落地实战篇

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;padding-right: 10px;padding-left: 10px;word-break: break-word;overflow-wrap: break-word;text-align: left;line-height: 1.25;color: rgb(43, 43, 43);font-family: Optima-Regular, Optima, PingFangTC-Light, PingFangSC-light, PingFangTC-light;letter-spacing: 2px;background-image: linear-gradient(90deg, rgba(50, 0, 0, 0.04) 3%, rgba(0, 0, 0, 0) 3%), linear-gradient(360deg, rgba(50, 0, 0, 0.04) 3%, rgba(0, 0, 0, 0) 3%);background-size: 20px 20px;background-position: center center;" data-mpa-powered-by="yiban.io"> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzkzMDI1NjcyOQ==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/EoJib2tNvVtf7icAmS0BQH6oDVG37Q8NzcfdguS5qAqOhfxvZyIKqmuX5BbnDjynrBbZzktp1EiaeFLzapp1nHysw/0?wx_fmt=png" data-nickname="码哥字节" data-alias="MageByte" data-signature="只写外面看不到的硬核文章,又有诗和远方。" data-from="0"></mpprofile> </section> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">目录<br></p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-size: 15px;color: #595959;list-style-type: circle;" class="list-paddingleft-2"> <li><p>登录实现</p></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: square;" class="list-paddingleft-2"> <li><p>B 端登录之后,浏览器存 cookie</p></li> <li><p>登录代码实现细节,cookie设计</p></li> </ul> <li><p>网关介绍</p></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: square;" class="list-paddingleft-2"> <li><p>API 网关是什么</p></li> <li><p>为什么需要网关</p></li> <li><p>从技术角度来看,什么是Kong?</p></li> <li><p>为什么使用 Kong</p></li> </ul> <li><p>Kong 网关解析 cookie</p></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: square;" class="list-paddingleft-2"> <li><p>kong 项目简介,流量转发</p></li> <li><p>鉴权 lua 脚本</p></li> <li><p>服务解析请求</p></li> </ul> <li><p>此方案实现的优缺点</p></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: square;" class="list-paddingleft-2"> <li><p>单点登录问题</p></li> <li><p>登录续期问题</p></li> <li><p>注销问题</p></li> </ul> </ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 22px;border-bottom: 4px solid rgb(64, 184, 250);"><span style="display: flex;width: 20px;height: 20px;background-size: 20px 20px;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hZQKMmugSsicqX0gKPcvJNhIuAjrqTf0XDBliaSXWnp7hjdptF5eG5Fqw/640?wx_fmt=png&quot;);margin-bottom: -22px;"></span><span style="display: flex;color: #40B8FA;font-size: 20px;margin-left: 25px;">登录实现</span><span style="display: flex;box-sizing: border-box;width: 200px;height: 10px;border-top-left-radius: 20px;background: RGBA(64, 184, 250, .5);color: rgb(255, 255, 255);font-size: 16px;letter-spacing: 0.544px;justify-content: flex-end;float: right;margin-top: -10px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <h3 data-tool="mdnice编辑器" style="color: black;font-size: 17px;font-weight: bold;text-align: center;margin-top: 20px;margin-bottom: 20px;"><span style="display: none;"></span><span style="border-bottom: 2px solid RGBA(79, 177, 249, .65);color: #2b2b2b;padding-bottom: 2px;"><span style="width: 30px;height: 30px;display: block;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hdlyonhXRjw1TEMYT7HbucGuqwooTqQMDpGIO6bza5QXmBj1xKYicPhQ/640?wx_fmt=png&quot;);background-position: center center;background-size: 30px;margin: auto auto -8px;opacity: 1;background-repeat: no-repeat;"></span>B 端登录之后,浏览器存 cookie</span><span style="display: none;"></span></h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.19558676028084251" src="/upload/fb6c541114984c677ed5acc72e951be.jpg" data-type="jpeg" data-w="997" style="border-radius: 6px;display: block;margin: 20px auto;object-fit: contain;box-shadow: rgb(153, 153, 153) 2px 4px 7px;"> <figcaption style="margin-top: 5px;text-align: center;font-size: 13px;"> <span style="background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hOdBZxuqP8nTMW9OlrI2ibEJD2rOMNjDFPI0pJw63dDL3n1o8ElvF7bA/640?wx_fmt=png&quot;);display: inline-block;width: 18px;height: 18px;background-size: 18px;background-repeat: no-repeat;background-position: center center;margin-right: 5px;margin-bottom: -5px;"></span>登录后的cookie </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">cookie 内容如下:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-size: 15px;color: #595959;list-style-type: circle;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> key: xxx_V2 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> value: 3001459%7C1636684996%7C7180720502%7Cb61a12ef865072964aa359e6a9ef2e0b1846dee9 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">value 分为四段值,由 %7C 隔开,这个Ascll码值是代表符号"|".</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">四段分别代表 userId, 时间戳 time, 随机数 nonce, 加密算法得到的 sign</p> <h3 data-tool="mdnice编辑器" style="color: black;font-size: 17px;font-weight: bold;text-align: center;margin-top: 20px;margin-bottom: 20px;"><span style="display: none;"></span><span style="border-bottom: 2px solid RGBA(79, 177, 249, .65);color: #2b2b2b;padding-bottom: 2px;"><span style="width: 30px;height: 30px;display: block;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hdlyonhXRjw1TEMYT7HbucGuqwooTqQMDpGIO6bza5QXmBj1xKYicPhQ/640?wx_fmt=png&quot;);background-position: center center;background-size: 30px;margin: auto auto -8px;opacity: 1;background-repeat: no-repeat;"></span>登录代码实现细节,cookie设计</span><span style="display: none;"></span></h3> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/1CHHx9Yq4nErFdibicDoe3bKrBic4ibIz4nTbflGBmy06fibBBdaDUqGgdCmxl03MHcg66Plxv9szW07WbTWsavJ4TjpZENUwpega/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;letter-spacing: 0px;padding-top: 15px;background: #282c34;border-radius: 5px;">/**<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;用户登录逻辑<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@global&nbsp;array&nbsp;<span style="color: #d19a66;line-height: 26px;">$_SESSION</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;<span style="color: #e6c07b;line-height: 26px;">type</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">$user_id</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/<br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;<span style="color: #c678dd;line-height: 26px;">function</span>&nbsp;do_login(<span style="color: #d19a66;line-height: 26px;">$user_id</span>)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;global&nbsp;<span style="color: #d19a66;line-height: 26px;">$_SESSION</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #d19a66;line-height: 26px;">$_SESSION</span>[<span style="color: #98c379;line-height: 26px;">"uid"</span>]&nbsp;=&nbsp;<span style="color: #d19a66;line-height: 26px;">$user_id</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;KZUser::add_auth_to_session(<span style="color: #d19a66;line-height: 26px;">$user_id</span>);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;更新帐号失败尝试次数<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #e6c07b;line-height: 26px;">unset</span>(<span style="color: #d19a66;line-height: 26px;">$_SESSION</span>[<span style="color: #98c379;line-height: 26px;">"login_try"</span>]);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #e6c07b;line-height: 26px;">unset</span>(<span style="color: #d19a66;line-height: 26px;">$_SESSION</span>[<span style="color: #98c379;line-height: 26px;">"need_vcode"</span>]);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//send&nbsp;the&nbsp;cookie<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #d19a66;line-height: 26px;">$login_time</span>&nbsp;=&nbsp;time();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #d19a66;line-height: 26px;">$nonce</span>&nbsp;=&nbsp;mt_rand(1000000000,&nbsp;9999999999);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #d19a66;line-height: 26px;">$cookie_params</span>&nbsp;=&nbsp;array(<span style="color: #d19a66;line-height: 26px;">$user_id</span>,&nbsp;<span style="color: #d19a66;line-height: 26px;">$login_time</span>,&nbsp;<span style="color: #d19a66;line-height: 26px;">$nonce</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;COOKIE_KEY&nbsp;即加密的密钥,和网关那边配置的一样<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #d19a66;line-height: 26px;">$cookie_params</span>[]&nbsp;=&nbsp;hash_hmac(<span style="color: #98c379;line-height: 26px;">"sha1"</span>,&nbsp;implode(<span style="color: #98c379;line-height: 26px;">""</span>,&nbsp;<span style="color: #d19a66;line-height: 26px;">$cookie_params</span>),&nbsp;COOKIE_KEY,&nbsp;<span style="color: #56b6c2;line-height: 26px;">false</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;测试环境特殊处理<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #d19a66;line-height: 26px;">$domain</span>&nbsp;=&nbsp;str_replace(<span style="color: #98c379;line-height: 26px;">".t1.com"</span>,&nbsp;DOMAIN_POSTFIX,&nbsp;COOKIE_DOMAIN);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;SESSION_COOKIE_NAME=xxx_V2<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setcookie(SESSION_COOKIE_NAME,&nbsp;implode(<span style="color: #98c379;line-height: 26px;">"|"</span>,&nbsp;<span style="color: #d19a66;line-height: 26px;">$cookie_params</span>),&nbsp;<span style="color: #d19a66;line-height: 26px;">$login_time</span>&nbsp;+&nbsp;604800,&nbsp;<span style="color: #98c379;line-height: 26px;">"/"</span>,&nbsp;<span style="color: #d19a66;line-height: 26px;">$domain</span>,&nbsp;<span style="color: #56b6c2;line-height: 26px;">false</span>,&nbsp;<span style="color: #56b6c2;line-height: 26px;">true</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">上面就是计算 setcookie 函数具体实现。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/1CHHx9Yq4nErFdibicDoe3bKrBic4ibIz4nTbflGBmy06fibBBdaDUqGgdCmxl03MHcg66Plxv9szW07WbTWsavJ4TjpZENUwpega/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;letter-spacing: 0px;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #d19a66;line-height: 26px;">$cookie_params</span>[]&nbsp;=&nbsp;hash_hmac(<span style="color: #98c379;line-height: 26px;">"sha1"</span>,&nbsp;implode(<span style="color: #98c379;line-height: 26px;">""</span>,&nbsp;<span style="color: #d19a66;line-height: 26px;">$cookie_params</span>),&nbsp;COOKIE_KEY,&nbsp;<span style="color: #56b6c2;line-height: 26px;">false</span>);<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">cookie 最后一个值 sign,会通过加密计算,利用 sha1 算法进行加密计算得到一个16 进制字符串得到sign。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">其中 COOKIE_KEY 即加密的密钥,和网关那边配置的一样。网关那边会通过同样的加密算法,加密参数,加密密钥进行加密计算,如果参数一样那么算出来的sign值会和cookie一致,那么说明是有效的cookie。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/1CHHx9Yq4nErFdibicDoe3bKrBic4ibIz4nTbflGBmy06fibBBdaDUqGgdCmxl03MHcg66Plxv9szW07WbTWsavJ4TjpZENUwpega/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;letter-spacing: 0px;padding-top: 15px;background: #282c34;border-radius: 5px;">&nbsp;setcookie(SESSION_COOKIE_NAME,&nbsp;implode(<span style="color: #98c379;line-height: 26px;">"|"</span>,&nbsp;<span style="color: #d19a66;line-height: 26px;">$cookie_params</span>),&nbsp;<span style="color: #d19a66;line-height: 26px;">$login_time</span>&nbsp;+&nbsp;604800,&nbsp;<span style="color: #98c379;line-height: 26px;">"/"</span>,&nbsp;<span style="color: #d19a66;line-height: 26px;">$domain</span>,&nbsp;<span style="color: #56b6c2;line-height: 26px;">false</span>,&nbsp;<span style="color: #56b6c2;line-height: 26px;">true</span>);<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">最后数组用"|"连接成一个字符串即得到前面的四段 cookie 值。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 22px;border-bottom: 4px solid rgb(64, 184, 250);"><span style="display: flex;width: 20px;height: 20px;background-size: 20px 20px;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hZQKMmugSsicqX0gKPcvJNhIuAjrqTf0XDBliaSXWnp7hjdptF5eG5Fqw/640?wx_fmt=png&quot;);margin-bottom: -22px;"></span><span style="display: flex;color: #40B8FA;font-size: 20px;margin-left: 25px;">网关介绍</span><span style="display: flex;box-sizing: border-box;width: 200px;height: 10px;border-top-left-radius: 20px;background: RGBA(64, 184, 250, .5);color: rgb(255, 255, 255);font-size: 16px;letter-spacing: 0.544px;justify-content: flex-end;float: right;margin-top: -10px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <h3 data-tool="mdnice编辑器" style="color: black;font-size: 17px;font-weight: bold;text-align: center;margin-top: 20px;margin-bottom: 20px;"><span style="display: none;"></span><span style="border-bottom: 2px solid RGBA(79, 177, 249, .65);color: #2b2b2b;padding-bottom: 2px;"><span style="width: 30px;height: 30px;display: block;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hdlyonhXRjw1TEMYT7HbucGuqwooTqQMDpGIO6bza5QXmBj1xKYicPhQ/640?wx_fmt=png&quot;);background-position: center center;background-size: 30px;margin: auto auto -8px;opacity: 1;background-repeat: no-repeat;"></span>API 网关是什么</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">API网关是随着微服务(Microservice)概念兴起的一种架构模式。原本一个庞大的单体应用(All in one)业务系统被拆分成许多微服务(Microservice)系统进行独立的维护和部署,服务拆分带来的变化是 API 的规模成倍增长,API的管理难度也在日益增加,使用API网关发布和管理API逐渐成为一种趋势。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">一般来说,API网关是运行于外部请求与内部服务之间的一个流量入口,实现对外部请求的<code style="overflow-wrap: break-word;margin-right: 2px;margin-left: 2px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 148, 247);background: rgba(59, 170, 250, 0.1);padding-right: 2px;padding-left: 2px;border-radius: 2px;height: 21px;line-height: 22px;">协议转换、鉴权、流控、参数校验、监控等通用功能</code>。</p> <h3 data-tool="mdnice编辑器" style="color: black;font-size: 17px;font-weight: bold;text-align: center;margin-top: 20px;margin-bottom: 20px;"><span style="display: none;"></span><span style="border-bottom: 2px solid RGBA(79, 177, 249, .65);color: #2b2b2b;padding-bottom: 2px;"><span style="width: 30px;height: 30px;display: block;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hdlyonhXRjw1TEMYT7HbucGuqwooTqQMDpGIO6bza5QXmBj1xKYicPhQ/640?wx_fmt=png&quot;);background-position: center center;background-size: 30px;margin: auto auto -8px;opacity: 1;background-repeat: no-repeat;"></span>为什么需要网关</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">微服务架构下,单体应用被切割成多个微服务,如果将所有的微服务直接对外暴露,势必会出现安全方面的各种问题。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">客户端如果可以直接向每个微服务发送请求,其问题主要如下:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-size: 15px;color: rgb(89, 89, 89);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> 客户端需求和每个微服务暴露的细粒度 API 不匹配。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> 每个公司可能有java,python,go多种语言,在不同的场景下又会使用不同的协议,部分服务使用的协议不是 Web 友好协议,可能使用 Thrift 二进制 RPC,也可能使用 AMQP 消息传递协议,或者其他的 grpc 之类的协议。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> 微服务的划分可能随着时间变化,微服务难以重构。如果合并两个服务,或者将一个服务拆分成两个或更多服务,这类重构就非常困难了。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> 不同的客户端可能需要不同的数据,例如 Web,H5,APP,Android,IOS。 </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">网关开源组件业内用的多的有 Zuul、SpringCloud Gateway、Kong、Nginx 等。</p> <h3 data-tool="mdnice编辑器" style="color: black;font-size: 17px;font-weight: bold;text-align: center;margin-top: 20px;margin-bottom: 20px;"><span style="display: none;"></span><span style="border-bottom: 2px solid RGBA(79, 177, 249, .65);color: #2b2b2b;padding-bottom: 2px;"><span style="width: 30px;height: 30px;display: block;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hdlyonhXRjw1TEMYT7HbucGuqwooTqQMDpGIO6bza5QXmBj1xKYicPhQ/640?wx_fmt=png&quot;);background-position: center center;background-size: 30px;margin: auto auto -8px;opacity: 1;background-repeat: no-repeat;"></span>从技术角度来看,什么是Kong?</span><span style="display: none;"></span></h3> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;text-size-adjust: 100%;line-height: 1.55em;border-radius: 6px;color: rgb(89, 89, 89);box-sizing: inherit;border-width: 1px;border-top-style: solid;border-right-style: solid;border-bottom-style: solid;border-color: rgba(64, 184, 250, 0.4);background: rgba(64, 184, 250, 0.1);"> <span style="color: RGBA(64, 184, 250, .5);font-size: 34px;line-height: 1;font-weight: 700;">❝</span> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;word-spacing: 2px;line-height: 26px;">这一段摘自KONG官方介绍文档<br>您可能已经听说过Kong基于Nginx,利用了其稳定性和高效率。但这究竟是怎么实现的呢?<br><br>更确切地说,Kong 是一个在 Nginx 中运行的 Lua 应用程序,并且可以通过 lua-nginx模块实现。</p> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;word-spacing: 2px;line-height: 26px;">Kong不是用这个模块编译Nginx,而是与 OpenResty 一起分发,OpenResty已经包含了lua-nginx-module。OpenResty 不是 Nginx 的分支,而是一组扩展其功能的模块。<br><br>这为可插拔架构奠定了基础,可以在运行时启用和执行Lua脚本(称为“插件”)。</p> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;word-spacing: 2px;line-height: 26px;">因此,我们认为Kong是微服务架构的典范:它的核心是实现数据库抽象,路由和插件管理。插件可以存在于单独的代码库中,并且可以在几行代码中注入到请求生命周期的任何位置。</p> <span style="float: right;color: RGBA(64, 184, 250, .5);">❞</span> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">简而言之,<code style="overflow-wrap: break-word;margin-right: 2px;margin-left: 2px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 148, 247);background: rgba(59, 170, 250, 0.1);padding-right: 2px;padding-left: 2px;border-radius: 2px;height: 21px;line-height: 22px;">Kong 是 Mashape 开源的高性能高可用 API 网关和 API 服务管理层,一款基于 Nginx_Lua 模块写的高可用服务网关,由于 Kong 是基于 Nginx 的,所以可以水平扩展多个 Kong 服务器。通过前置的负载均衡配置把请求均匀地分发到各个 Server,来应对大批量的网络请求。</code></p> <h3 data-tool="mdnice编辑器" style="color: black;font-size: 17px;font-weight: bold;text-align: center;margin-top: 20px;margin-bottom: 20px;"><span style="display: none;"></span><span style="border-bottom: 2px solid RGBA(79, 177, 249, .65);color: #2b2b2b;padding-bottom: 2px;"><span style="width: 30px;height: 30px;display: block;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hdlyonhXRjw1TEMYT7HbucGuqwooTqQMDpGIO6bza5QXmBj1xKYicPhQ/640?wx_fmt=png&quot;);background-position: center center;background-size: 30px;margin: auto auto -8px;opacity: 1;background-repeat: no-repeat;"></span>为什么使用 Kong</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">在众多 API GATEWAY 框架中,Mashape 开源的高性能高可用 API 网关和 API 服务管理层——KONG(基于 NGINX)特点尤为突出,它可以通过插件扩展已有功能,这些插件(使用 lua 编写)在API请求响应循环的生命周期中被执行。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">于此同时,KONG本身提供包括 HTTP 基本认证、密钥认证、CORS、TCP、UDP、文件日志、API请求限流、请求转发及 NGINX 监控等基本功能。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">除了Kong的基本网关功能,Kong 的云原生属性:与平台无关,Kong 可以从裸机运行到 Kubernetes,是我们青睐的原因,我们的服务都是 k8s 部署调度的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">Kong 经常用到的术语有:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-size: 15px;color: #595959;list-style-type: circle;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> client : 指下游客户向 Kong 代理端口发出请求。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> upstream service :指自己位于 Kong 后面的 API/Service,客户端请求被转发到这些API/Service。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> Service : 顾名思义,服务实体是上游服务的抽象。服务的示例包括数据转换微服务、计费API等。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> Route : 这是指 Kong 路由实体。Route 是进入 Kong 的入口点,并为要匹配的请求定义规则,然后路由到给定的服务。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> Plugin : 指 Kong 的 “plugins”,它是在代理生命周期中运行的业务逻辑片段。插件可以通过管理 API 进行配置——可以是全局的(所有传入的流量),也可以是在特定的路由和服务上配置。 </section></li> </ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 22px;border-bottom: 4px solid rgb(64, 184, 250);"><span style="display: flex;width: 20px;height: 20px;background-size: 20px 20px;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hZQKMmugSsicqX0gKPcvJNhIuAjrqTf0XDBliaSXWnp7hjdptF5eG5Fqw/640?wx_fmt=png&quot;);margin-bottom: -22px;"></span><span style="display: flex;color: #40B8FA;font-size: 20px;margin-left: 25px;">Kong 网关解析 cookie</span><span style="display: flex;box-sizing: border-box;width: 200px;height: 10px;border-top-left-radius: 20px;background: RGBA(64, 184, 250, .5);color: rgb(255, 255, 255);font-size: 16px;letter-spacing: 0.544px;justify-content: flex-end;float: right;margin-top: -10px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <h3 data-tool="mdnice编辑器" style="color: black;font-size: 17px;font-weight: bold;text-align: center;margin-top: 20px;margin-bottom: 20px;"><span style="display: none;"></span><span style="border-bottom: 2px solid RGBA(79, 177, 249, .65);color: #2b2b2b;padding-bottom: 2px;"><span style="width: 30px;height: 30px;display: block;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hdlyonhXRjw1TEMYT7HbucGuqwooTqQMDpGIO6bza5QXmBj1xKYicPhQ/640?wx_fmt=png&quot;);background-position: center center;background-size: 30px;margin: auto auto -8px;opacity: 1;background-repeat: no-repeat;"></span>kong 项目简介,流量转发</span><span style="display: none;"></span></h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="1.6023809523809525" src="/upload/e0213917d4421f4dc6a2c18c87954306.jpg" data-type="jpeg" data-w="840" style="border-radius: 6px;display: block;margin: 20px auto;object-fit: contain;box-shadow: rgb(153, 153, 153) 2px 4px 7px;"> <figcaption style="margin-top: 5px;text-align: center;font-size: 13px;"> <span style="background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hOdBZxuqP8nTMW9OlrI2ibEJD2rOMNjDFPI0pJw63dDL3n1o8ElvF7bA/640?wx_fmt=png&quot;);display: inline-block;width: 18px;height: 18px;background-size: 18px;background-repeat: no-repeat;background-position: center center;margin-right: 5px;margin-bottom: -5px;"></span>Kong 项目构成 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">这个项目只是做了鉴权,属于内网网关,流量在这之前还会经过一道外网网关,那边有流控,请求分发,配置证书等功能,内网网关只是做鉴权,流量打到这边鉴权之后不同的路由转发到 k8s 的不同 service 里调用具体的服务。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">项目部署了线上网关和测试环境网关两种环境,提供的plugins插件鉴权有 APP端的鉴权,C端和B端鉴权,这里我主要讲的是B端的鉴权,其他的简单介绍一下:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-size: 15px;color: #595959;list-style-type: circle;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> shop-resolve 里面主要是 小程序和H5 两种环境下的店铺信息鉴权,是公司一个电商项目需要用的; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> idk-client-type-resolve 里面主要是 小程序和H5 两种环境下的访问鉴权; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> health-check 没什么好说的,是k8s的健康检查需要的 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> 其他三个 app-resolve,buser-reslove,cuser-resolve 分别是app环境,B端,C端的鉴权 </section></li> </ul> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.31043478260869567" src="/upload/68fe4664a2be3b6977182376dadd6110.jpg" data-type="jpeg" data-w="2300" style="border-radius: 6px;display: block;margin: 20px auto;object-fit: contain;box-shadow: rgb(153, 153, 153) 2px 4px 7px;"> <figcaption style="margin-top: 5px;text-align: center;font-size: 13px;"> <span style="background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hOdBZxuqP8nTMW9OlrI2ibEJD2rOMNjDFPI0pJw63dDL3n1o8ElvF7bA/640?wx_fmt=png&quot;);display: inline-block;width: 18px;height: 18px;background-size: 18px;background-repeat: no-repeat;background-position: center center;margin-right: 5px;margin-bottom: -5px;"></span>kong.ymal-service </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">kong.ymal 里面配置了很多业务线的 Service,比如快站云服务可以通过路由(www.kuaizhan.com,cloud.kuaizhan.com)过来,配置里面使用了鉴权插件 bUser-resolve,根据这个 name 配置请求转发 upstream service 如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.08541973490427099" src="/upload/511b3238262901a81f469504dfa9c3e2.jpg" data-type="jpeg" data-w="1358" style="border-radius: 6px;display: block;margin: 20px auto;object-fit: contain;box-shadow: rgb(153, 153, 153) 2px 4px 7px;"> <figcaption style="margin-top: 5px;text-align: center;font-size: 13px;"> <span style="background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hOdBZxuqP8nTMW9OlrI2ibEJD2rOMNjDFPI0pJw63dDL3n1o8ElvF7bA/640?wx_fmt=png&quot;);display: inline-block;width: 18px;height: 18px;background-size: 18px;background-repeat: no-repeat;background-position: center center;margin-right: 5px;margin-bottom: -5px;"></span>kong.ymal-upstream service </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">upstream service 指自己位于 Kong 后面的 API/Service,客户端请求被转发到这些API/Service,此处是转发到 k8s 的 service 流量入口到具体的服务处理请求。</p> <h3 data-tool="mdnice编辑器" style="color: black;font-size: 17px;font-weight: bold;text-align: center;margin-top: 20px;margin-bottom: 20px;"><span style="display: none;"></span><span style="border-bottom: 2px solid RGBA(79, 177, 249, .65);color: #2b2b2b;padding-bottom: 2px;"><span style="width: 30px;height: 30px;display: block;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hdlyonhXRjw1TEMYT7HbucGuqwooTqQMDpGIO6bza5QXmBj1xKYicPhQ/640?wx_fmt=png&quot;);background-position: center center;background-size: 30px;margin: auto auto -8px;opacity: 1;background-repeat: no-repeat;"></span>鉴权 lua 脚本</span><span style="display: none;"></span></h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.5250364608653378" src="/upload/eb0332826849785e60ce8cdfe34743fd.jpg" data-type="jpeg" data-w="2057" style="border-radius: 6px;display: block;margin: 20px auto;object-fit: contain;box-shadow: rgb(153, 153, 153) 2px 4px 7px;"> <figcaption style="margin-top: 5px;text-align: center;font-size: 13px;"> <span style="background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hOdBZxuqP8nTMW9OlrI2ibEJD2rOMNjDFPI0pJw63dDL3n1o8ElvF7bA/640?wx_fmt=png&quot;);display: inline-block;width: 18px;height: 18px;background-size: 18px;background-repeat: no-repeat;background-position: center center;margin-right: 5px;margin-bottom: -5px;"></span>B端鉴权lua脚本 </figcaption> </figure> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/1CHHx9Yq4nErFdibicDoe3bKrBic4ibIz4nTbflGBmy06fibBBdaDUqGgdCmxl03MHcg66Plxv9szW07WbTWsavJ4TjpZENUwpega/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;letter-spacing: 0px;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #e6c07b;line-height: 26px;">local</span>&nbsp;ngx_re&nbsp;=&nbsp;require&nbsp;<span style="color: #98c379;line-height: 26px;">"ngx.re"</span><br><span style="color: #e6c07b;line-height: 26px;">local</span>&nbsp;BasePlugin&nbsp;=&nbsp;require&nbsp;<span style="color: #98c379;line-height: 26px;">"kong.plugins.base_plugin"</span><br><span style="color: #e6c07b;line-height: 26px;">local</span>&nbsp;string&nbsp;=&nbsp;require&nbsp;<span style="color: #98c379;line-height: 26px;">"resty.string"</span><br><span style="color: #e6c07b;line-height: 26px;">local</span>&nbsp;BuserResolveHandler&nbsp;=&nbsp;BasePlugin:extend()<br><br><span style="color: #c678dd;line-height: 26px;">function</span>&nbsp;BuserResolveHandler:new()<br>&nbsp;&nbsp;&nbsp;&nbsp;BuserResolveHandler.super.new(self,&nbsp;<span style="color: #98c379;line-height: 26px;">"buser-resolve"</span>)<br>end<br><br><span style="color: #c678dd;line-height: 26px;">function</span>&nbsp;BuserResolveHandler:access(conf)<br>&nbsp;&nbsp;&nbsp;&nbsp;BuserResolveHandler.super.access(self)<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #e6c07b;line-height: 26px;">local</span>&nbsp;cookieName&nbsp;=&nbsp;<span style="color: #98c379;line-height: 26px;">"cookie_"</span>&nbsp;..&nbsp;<span style="color: #98c379;line-height: 26px;">"KUAIZHAN_V2"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #e6c07b;line-height: 26px;">local</span>&nbsp;kuaizhanV2&nbsp;=&nbsp;ngx.var[cookieName]<br>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ngx.log(ngx.ERR,&nbsp;<span style="color: #98c379;line-height: 26px;">"kuaizhanV2"</span>,&nbsp;kuaizhanV2)<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #e6c07b;line-height: 26px;">local</span>&nbsp;uid&nbsp;=&nbsp;0<br>&nbsp;&nbsp;&nbsp;&nbsp;ngx.req.set_header(<span style="color: #98c379;line-height: 26px;">"X-User-Id"</span>,&nbsp;uid)<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;cookie&nbsp;内容&nbsp;3001459%7C1636684996%7C7180720502%7Cb61a12ef865072964aa359e6a9ef2e0b1846dee9<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;xxx_V2&nbsp;and&nbsp;xxx_V2&nbsp;~=&nbsp;<span style="color: #98c379;line-height: 26px;">''</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">then</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #e6c07b;line-height: 26px;">local</span>&nbsp;res,&nbsp;err&nbsp;=&nbsp;ngx_re.split(xxxV2,&nbsp;<span style="color: #98c379;line-height: 26px;">"%7C"</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;err&nbsp;<span style="color: #c678dd;line-height: 26px;">then</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #e6c07b;line-height: 26px;">return</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;解析得到&nbsp;userId,&nbsp;time,&nbsp;nonce,&nbsp;sign,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;分别为&nbsp;3001459,1636684996,7180720502,b61a12ef865072964aa359e6a9ef2e0b1846dee9<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #e6c07b;line-height: 26px;">local</span>&nbsp;userId,&nbsp;time,&nbsp;nonce,&nbsp;sign&nbsp;=&nbsp;res[1],&nbsp;res[2],&nbsp;res[3],&nbsp;res[4]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;根据密钥,时间,签名,利用&nbsp;hmac_sha1&nbsp;算法,十六进制算法,得到摘要签名<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #e6c07b;line-height: 26px;">local</span>&nbsp;digest&nbsp;=&nbsp;ngx.hmac_sha1(conf.secret,&nbsp;userId&nbsp;..&nbsp;time&nbsp;..&nbsp;nonce)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #e6c07b;line-height: 26px;">local</span>&nbsp;theSign&nbsp;=&nbsp;string.to_hex(digest)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--&nbsp;TODO&nbsp;加上过期时间判断<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;计算签名和cookie解析得到sign&nbsp;是否相同,相同则赋值uid<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;theSign&nbsp;==&nbsp;sign&nbsp;<span style="color: #c678dd;line-height: 26px;">then</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uid&nbsp;=&nbsp;userId<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ngx.log(ngx.ERR,&nbsp;<span style="color: #98c379;line-height: 26px;">"theSign:"</span>,&nbsp;theSign,&nbsp;<span style="color: #98c379;line-height: 26px;">"sign:"</span>,&nbsp;sign,&nbsp;<span style="color: #98c379;line-height: 26px;">"uid:"</span>,&nbsp;uid)<br>&nbsp;&nbsp;&nbsp;&nbsp;end<br><br>&nbsp;&nbsp;&nbsp;&nbsp;ngx.log(ngx.ERR,&nbsp;<span style="color: #98c379;line-height: 26px;">"get&nbsp;x-user-id:"</span>&nbsp;..&nbsp;uid)<br>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;nginx&nbsp;请求头header里面存放&nbsp;X-User-Id,再转发到各个业务线<br>&nbsp;&nbsp;&nbsp;&nbsp;ngx.req.set_header(<span style="color: #98c379;line-height: 26px;">"X-User-Id"</span>,&nbsp;uid)<br>end<br><br><span style="color: #e6c07b;line-height: 26px;">return</span>&nbsp;BuserResolveHandler<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">解析过程如下四步:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-size: 15px;color: #595959;list-style-type: circle;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> cookie 内容 3001459%7C1636684996%7C7180720502%7Cb61a12ef865072964aa359e6a9ef2e0b1846dee9 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> 解析得到 userId, time, nonce, sign, 分别为 3001459,1636684996,7180720502,b61a12ef865072964aa359e6a9ef2e0b1846dee9 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> 根据密钥,用户id,时间,随机数,利用 hmac_sha1 算法,十六进制算法,得到摘要签名,计算签名和cookie解析得到sign 是否相同,相同则赋值uid </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> nginx 请求头header里面存放 X-User-Id,再转发到各个k8s service 中去(k8s service是各个服务集群的流量入口) </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">conf.secret 里面配置的密钥,很多业务线公用一个登录的话,比如官网很多业务线,那么插件的 secret 都是一样的配置,同理,这个 secret 和刚刚设置 cookie 的时候,使用的是一个值。</p> <h3 data-tool="mdnice编辑器" style="color: black;font-size: 17px;font-weight: bold;text-align: center;margin-top: 20px;margin-bottom: 20px;"><span style="display: none;"></span><span style="border-bottom: 2px solid RGBA(79, 177, 249, .65);color: #2b2b2b;padding-bottom: 2px;"><span style="width: 30px;height: 30px;display: block;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hdlyonhXRjw1TEMYT7HbucGuqwooTqQMDpGIO6bza5QXmBj1xKYicPhQ/640?wx_fmt=png&quot;);background-position: center center;background-size: 30px;margin: auto auto -8px;opacity: 1;background-repeat: no-repeat;"></span>服务解析请求</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">因为这种方式在网关层就实现了在 header 里面设置了用户id信息,到了各个业务方直接写一个解析器解析请求头的 userId;</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">然后写一个注解类似于 @LoginRequired 的自定义注解,配合变量 BUser 来使用,这个 BUser 对象里就包含解析得到的 userId;</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">最后注解作用于 controller 接口,就可以完成请求的登录信息拦截了。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">由于这个实现太偏业务,而且比较简单这里就不贴具体的代码实现了。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 22px;border-bottom: 4px solid rgb(64, 184, 250);"><span style="display: flex;width: 20px;height: 20px;background-size: 20px 20px;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hZQKMmugSsicqX0gKPcvJNhIuAjrqTf0XDBliaSXWnp7hjdptF5eG5Fqw/640?wx_fmt=png&quot;);margin-bottom: -22px;"></span><span style="display: flex;color: #40B8FA;font-size: 20px;margin-left: 25px;">此方案实现的优缺点</span><span style="display: flex;box-sizing: border-box;width: 200px;height: 10px;border-top-left-radius: 20px;background: RGBA(64, 184, 250, .5);color: rgb(255, 255, 255);font-size: 16px;letter-spacing: 0.544px;justify-content: flex-end;float: right;margin-top: -10px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">优点:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-size: 15px;color: rgb(89, 89, 89);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> 实现简单,易维护易懂 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;font-size: 14px;"> 可以实现统一网关鉴权和流量分发 </section></li> </ol> <h3 data-tool="mdnice编辑器" style="color: black;font-size: 17px;font-weight: bold;text-align: center;margin-top: 20px;margin-bottom: 20px;"><span style="display: none;"></span><span style="border-bottom: 2px solid RGBA(79, 177, 249, .65);color: #2b2b2b;padding-bottom: 2px;"><span style="width: 30px;height: 30px;display: block;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hdlyonhXRjw1TEMYT7HbucGuqwooTqQMDpGIO6bza5QXmBj1xKYicPhQ/640?wx_fmt=png&quot;);background-position: center center;background-size: 30px;margin: auto auto -8px;opacity: 1;background-repeat: no-repeat;"></span>单点登录问题</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">一个企业一般情况下只有一个域名,通过二级域名区分不同的系统。比如我们主域名叫做 xxx.com,另一个业务线有个二级域名 aaa.xxx.com,现在要实现在官网登录了,那么也就在另一个业务线登录了。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">实现如下:</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">登录以后,可以将Cookie的域设置为顶域 xxx.com,这样所有子域的系统都可以访问到顶域的 Cookie。我们在设置 Cookie 时,只能设置顶域和自己的域,不能设置其他的域。因此这边另一个业务线可以直接访问到顶域的登录状态,然后在 kong 解析那边的访问请求,密钥设置成一样的就可以鉴权了。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">但是多端,或者跨顶域情况下的单点登录是没法做的。</p> <h3 data-tool="mdnice编辑器" style="color: black;font-size: 17px;font-weight: bold;text-align: center;margin-top: 20px;margin-bottom: 20px;"><span style="display: none;"></span><span style="border-bottom: 2px solid RGBA(79, 177, 249, .65);color: #2b2b2b;padding-bottom: 2px;"><span style="width: 30px;height: 30px;display: block;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hdlyonhXRjw1TEMYT7HbucGuqwooTqQMDpGIO6bza5QXmBj1xKYicPhQ/640?wx_fmt=png&quot;);background-position: center center;background-size: 30px;margin: auto auto -8px;opacity: 1;background-repeat: no-repeat;"></span>登录续期问题</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">不知道大家有没有关注到第一张 cookie 截图后面有个失效时间,这种由于依赖 cookie,因此只要到期就会被踢下线,需要重新登录,一定程度上影响客户体验。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">现在的很多应用都利用 token + redis 方案实现了登录续期,例如连续十天内有过登录,那么不需要再次登录,后端实现自动续期,十天以上都没有登录过的才失效需要重新登录。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">但是续期服务需要 redis 成本,这种省成本。</p> <h3 data-tool="mdnice编辑器" style="color: black;font-size: 17px;font-weight: bold;text-align: center;margin-top: 20px;margin-bottom: 20px;"><span style="display: none;"></span><span style="border-bottom: 2px solid RGBA(79, 177, 249, .65);color: #2b2b2b;padding-bottom: 2px;"><span style="width: 30px;height: 30px;display: block;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/5ic2qggSMqHl9lQ0sW7U8CNrc1WWicab8hdlyonhXRjw1TEMYT7HbucGuqwooTqQMDpGIO6bza5QXmBj1xKYicPhQ/640?wx_fmt=png&quot;);background-position: center center;background-size: 30px;margin: auto auto -8px;opacity: 1;background-repeat: no-repeat;"></span>注销问题</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">这种方案的注销,只是简单的删除 cookie,如果有心人拿到 cookie 仍然是可以用的,这个 cookie 在有效期内不会失效。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">token+redis 方案可以做到真实的 token 失效。</p> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzkzMDI1NjcyOQ==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/EoJib2tNvVtf7icAmS0BQH6oDVG37Q8NzcfdguS5qAqOhfxvZyIKqmuX5BbnDjynrBbZzktp1EiaeFLzapp1nHysw/0?wx_fmt=png" data-nickname="码哥字节" data-alias="MageByte" data-signature="只写外面看不到的硬核文章,又有诗和远方。" data-from="0"></mpprofile> <span style="font-size: 14px;word-spacing: 2px;text-align: left;"></span> </section> </section> <p><br></p>

Redis 分布式锁的正确实现原理演化历程与 Redisson 实战总结

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" data-mpa-powered-by="yiban.io"> <section data-mpa-template="t" mpa-from-tpl="t"> <section style="display: flex;justify-content: center;align-items: center;width: 100%;justify-content: flex-start;padding-left: 34px;" data-mid="" mpa-from-tpl="t"> <section style="display: flex;justify-content: flex-start;align-items: center;flex-direction: column;" data-mid="" mpa-from-tpl="t"> <section style="width: 8px;height: 3px;align-self: flex-end;transform: translateY(-28px);margin-right: -4px;" data-mid="" mpa-from-tpl="t"> <img class="rich_pages wxw-img" data-ratio="0.875" src="/upload/ca621f85a55151157be89ea6853d30e3.png" data-type="png" data-w="16" style="display: block;"> </section> </section> </section> </section> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzkzMDI1NjcyOQ==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/EoJib2tNvVtf7icAmS0BQH6oDVG37Q8NzcfdguS5qAqOhfxvZyIKqmuX5BbnDjynrBbZzktp1EiaeFLzapp1nHysw/0?wx_fmt=png" data-nickname="码哥字节" data-alias="MageByte" data-signature="只写外面看不到的硬核文章,又有诗和远方。" data-from="0"></mpprofile> </section> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding: 10px 10px 10px 20px;border-width: 1px;border-top-style: solid;border-right-style: solid;border-bottom-style: solid;border-color: rgb(255, 191, 82);color: rgb(106, 115, 125);line-height: 1.75em;font-size: 0.9em;box-sizing: inherit;font-family: Roboto, Oxygen, Ubuntu, Cantarell, PingFangSC-light, PingFangTC-light, &quot;Open Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;text-align: left;white-space: normal;overflow: auto;text-size-adjust: 100%;border-radius: 5px;background: rgb(255, 248, 230);"> <span style="margin-left: -15px;color: rgb(244, 138, 0);font-size: 32px;line-height: 0.6;">❝</span> <p style="margin-top: -15px;padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;line-height: 26px;color: rgba(0, 0, 0, 0.85);"><span style="font-size: 14px;">可能是最完善的&nbsp;Redis 分布式锁原理与实战总结,建议收藏,文末<strong>送书福利</strong></span></p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">Redis 分布式锁使用 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">SET</code> 指令就可以实现了么?在分布式领域 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">CAP</code> 理论一直存在。<br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">分布式锁的门道可没那么简单,我们在网上看到的分布式锁方案可能是有问题的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">「码哥」一步步带你深入分布式锁是如何一步步完善,在高并发生产环境中如何正确使用分布式锁。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">在进入正文之前,我们先带着问题去思考:</p> <ul data-tool="mdnice编辑器" style="font-size: 15px;margin-top: 8px;margin-bottom: 8px;padding-left: 20px;color: rgb(255, 191, 82);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 什么时候需要分布式锁? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 加、解锁的代码位置有讲究么? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 如何避免出现锁再也无法删除? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 超时时间设置多少合适呢? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 如何避免锁被其他线程释放 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 如何实现重入锁? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 主从架构会带来什么安全问题? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 什么是 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">Redlock</code> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> Redisson 分布式锁最佳实战 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 看门狗实现原理 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> …… </section></li> </ul> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> <br> </section> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);text-align: center;"> <span style="color: rgb(244, 138, 0);font-size: 22px;font-weight: bold;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">什么时候用分布式锁?</span> <br> </section> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;text-size-adjust: 100%;line-height: 1.75em;border-radius: 5px;box-sizing: inherit;border-width: 1px;border-top-style: solid;border-right-style: solid;border-bottom-style: solid;border-color: rgb(255, 191, 82);background: rgb(255, 248, 230);"> <span style="color: #f48a00;font-size: 32px;line-height: 0.6;margin-left: -15px;">❝</span> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;line-height: 26px;margin-top: -15px;color: rgba(0, 0, 0, 0.85);">码哥,说个通俗的例子讲解下什么时候需要分布式锁呢?</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">诊所只有一个医生,很多患者前来就诊。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">医生在同一时刻只能给一个患者提供就诊服务。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">如果不是这样的话,就会出现医生在就诊肾亏的「肖菜鸡」准备开药时候患者切换成了脚臭的「谢霸哥」,这时候药就被谢霸哥取走了。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">治肾亏的药被有脚臭的拿去了。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">当并发去读写一个【共享资源】的时候,我们为了保证数据的正确,需要控制同一时刻只有一个线程访问。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);"><strong>分布式锁就是用来控制同一时刻,只有一个 JVM 进程中的一个线程可以访问被保护的资源。</strong></p> <h1 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 24px;text-align: center;line-height: 95px;margin-top: 10px;margin-bottom: 10px;"><span style="font-size: 22px;color: #f48a00;border-bottom: 2px solid #ffbf52;">分布式锁入门</span></h1> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;text-size-adjust: 100%;line-height: 1.75em;border-radius: 5px;box-sizing: inherit;border-width: 1px;border-top-style: solid;border-right-style: solid;border-bottom-style: solid;border-color: rgb(255, 191, 82);background: rgb(255, 248, 230);"> <span style="color: #f48a00;font-size: 32px;line-height: 0.6;margin-left: -15px;">❝</span> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;line-height: 26px;margin-top: -15px;color: rgba(0, 0, 0, 0.85);">65 哥:分布式锁应该满足哪些特性?</p> </blockquote> <ol data-tool="mdnice编辑器" style="font-size: 15px;margin-top: 8px;margin-bottom: 8px;padding-left: 20px;color: rgb(255, 191, 82);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 互斥:在任何给定时刻,只有一个客户端可以持有锁; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 无死锁:任何时刻都有可能获得锁,即使获取锁的客户端崩溃; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 容错:只要大多数 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">Redis</code>的节点都已经启动,客户端就可以获取和释放锁。 </section></li> </ol> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;text-size-adjust: 100%;line-height: 1.75em;border-radius: 5px;box-sizing: inherit;border-width: 1px;border-top-style: solid;border-right-style: solid;border-bottom-style: solid;border-color: rgb(255, 191, 82);background: rgb(255, 248, 230);"> <span style="color: #f48a00;font-size: 32px;line-height: 0.6;margin-left: -15px;">❝</span> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;line-height: 26px;margin-top: -15px;color: rgba(0, 0, 0, 0.85);">码哥,我可以使用 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">SETNX key value</code> 命令是实现「互斥」特性。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">这个命令来自于<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">SET if Not eXists</code>的缩写,意思是:如果 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">key</code> 不存在,则设置 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">value</code> 给这个<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">key</code>,否则啥都不做。Redis 官方地址说的:</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">命令的返回值:</p> <ul data-tool="mdnice编辑器" style="font-size: 15px;margin-top: 8px;margin-bottom: 8px;padding-left: 20px;color: rgb(255, 191, 82);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 1:设置成功; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 0:key 没有设置成功。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">如下场景:</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">敲代码一天累了,想去放松按摩下肩颈。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">168 号技师最抢手,大家喜欢点,所以并发量大,需要分布式锁控制。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">同一时刻只允许一个「客户」预约 168 技师。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">肖菜鸡申请 168 技师成功:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;">&gt;&nbsp;SETNX&nbsp;lock:168&nbsp;1<br>(<span style="color: #a6e22e;line-height: 26px;">integer</span>)&nbsp;1&nbsp;<span style="color: #75715e;line-height: 26px;">#&nbsp;获取 168 技师成功</span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">谢霸哥后面到,申请失败:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;">&gt;&nbsp;SETNX&nbsp;lock&nbsp;2<br>(<span style="color: #a6e22e;line-height: 26px;">integer</span>)&nbsp;0&nbsp;<span style="color: #75715e;line-height: 26px;">#&nbsp;客户谢霸哥&nbsp;2&nbsp;获取失败</span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">此刻,申请成功的客户就可以享受 168 技师的肩颈放松服务「共享资源」。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">享受结束后,要及时释放锁,给后来者享受 168 技师的服务机会。</p> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;text-size-adjust: 100%;line-height: 1.75em;border-radius: 5px;box-sizing: inherit;border-width: 1px;border-top-style: solid;border-right-style: solid;border-bottom-style: solid;border-color: rgb(255, 191, 82);background: rgb(255, 248, 230);"> <span style="color: #f48a00;font-size: 32px;line-height: 0.6;margin-left: -15px;">❝</span> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;line-height: 26px;margin-top: -15px;color: rgba(0, 0, 0, 0.85);">肖菜鸡,码哥考考你如何释放锁呢?</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">很简单,使用 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">DEL</code> 删除这个 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">key</code> 就行。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-over

SpringCloud 分布式日志采集方案

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">由于微服务架构中每个服务可能分散在不同的服务器上,因此需要一套分布式日志的解决方案。spring-cloud提供了一个用来trace服务的组件sleuth。它可以通过日志获得服务的依赖关系。基于sleuth,可以通过现有的日志工具实现分布式日志的采集。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">这里使用的是ELK,也就是elasticsearch、logstash、kibana。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 40px;margin-bottom: 20px;font-weight: bold;line-height: 1.5;color: rgb(63, 63, 63);font-size: 120%;"><span style="display: none;"></span>一、sleuth<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;"><strong style="color: rgb(255, 53, 2);line-height: 1.5;">第一步:sleuth管理端</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">sleuth一般单独放在一个工程中。需要添加如下依赖</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">dependency</span>&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">groupId</span>&gt;</span>io.zipkin.java<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">groupId</span>&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">artifactId</span>&gt;</span>zipkin-autoconfigure-ui<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">artifactId</span>&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">scope</span>&gt;</span>runtime<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">scope</span>&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">dependency</span>&gt;</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">dependency</span>&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">groupId</span>&gt;</span>io.zipkin.java<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">groupId</span>&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">artifactId</span>&gt;</span>zipkin-server<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">artifactId</span>&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">dependency</span>&gt;</span>&nbsp;&nbsp;<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">配置服务注册中心的地址</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #d19a66;line-height: 26px;">eureka:</span>&nbsp;<br>&nbsp;&nbsp;<span style="color: #d19a66;line-height: 26px;">client:</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #d19a66;line-height: 26px;">serviceUrl:</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #d19a66;line-height: 26px;">defaultZone:</span>&nbsp;<span style="color: #98c379;line-height: 26px;">http://localhost:1111/eureka/</span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">启动类加入服务发现的注解和zipkin的注解,如下</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #c678dd;line-height: 26px;">package</span>&nbsp;com.wlf.demo;<br>&nbsp;<br><span style="color: #c678dd;line-height: 26px;">import</span>&nbsp;org.springframework.boot.SpringApplication;<br><span style="color: #c678dd;line-height: 26px;">import</span>&nbsp;org.springframework.boot.autoconfigure.SpringBootApplication;<br><span style="color: #c678dd;line-height: 26px;">import</span>&nbsp;org.springframework.cloud.client.discovery.EnableDiscoveryClient;<br>&nbsp;<br><span style="color: #c678dd;line-height: 26px;">import</span>&nbsp;zipkin.server.EnableZipkinServer;<br>&nbsp;<br><span style="color: #61aeee;line-height: 26px;">@EnableDiscoveryClient</span>&nbsp;<br><span style="color: #61aeee;line-height: 26px;">@EnableZipkinServer</span>&nbsp;&nbsp;<br><span style="color: #61aeee;line-height: 26px;">@SpringBootApplication</span>&nbsp;&nbsp;<br><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">Application</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">void</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">main</span><span style="line-height: 26px;">(String[]&nbsp;args)</span>&nbsp;</span>{&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SpringApplication.run(Application<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>,&nbsp;<span style="color: #e6c07b;line-height: 26px;">args</span>)</span>;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br>&nbsp;<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">这个时候启动并访问该微服务的地址,可以看到zipkin的管理页面了</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;"><strong style="color: rgb(255, 53, 2);line-height: 1.5;">第二步:被管理的微服务端</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">在我们的其他微服务端需要简单的配置,纳入到zipkin的管理之中</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">引入依赖</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">dependency</span>&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">groupId</span>&gt;</span>org.springframework.cloud<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">groupId</span>&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">artifactId</span>&gt;</span>spring-cloud-starter-sleuth<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">artifactId</span>&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">dependency</span>&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">dependency</span>&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">groupId</span>&gt;</span>org.springframework.cloud<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">groupId</span>&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">artifactId</span>&gt;</span>spring-cloud-sleuth-zipkin<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">artifactId</span>&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">dependency</span>&gt;</span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">加入如下配置</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #d19a66;line-height: 26px;">spring:</span>&nbsp;<br>&nbsp;&nbsp;<span style="color: #d19a66;line-height: 26px;">sleuth:</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #d19a66;line-height: 26px;">sampler:</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #d19a66;line-height: 26px;">percentage:</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">1</span><br>&nbsp;&nbsp;<span style="color: #d19a66;line-height: 26px;">zipkin:</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #d19a66;line-height: 26px;">base-url:</span>&nbsp;<span style="color: #98c379;line-height: 26px;">http://localhost:9411</span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;"><code style="margin-right: 2px;margin-left: 2px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;background: rgb(248, 245, 236);color: rgb(255, 53, 2);line-height: 1.5;font-size: 90%;padding: 3px 5px;border-radius: 2px;">spring.sleuth.sampler.percentage</code>:这个参数的意思是抓取100%的日志,只有通过抓取日志,才能获知依赖关系。但是如果始终抓取日志的话对性能会有影响,因此可以自己配置。一般在开发环境,该值设置为1,生产环境视情况而定。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;"><code style="margin-right: 2px;margin-left: 2px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;background: rgb(248, 245, 236);color: rgb(255, 53, 2);line-height: 1.5;font-size: 90%;padding: 3px 5px;border-radius: 2px;">spring.zipkin.base-url</code>:为第一步配置的zipkin管理端微服务的地址</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">现在分别启动服务注册中心,网关,需要的微服务,以及sleuth。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">随便调用一个微服务</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.48547008547008547" src="/upload/f3376a3fdd65b8ee8812f0ec5f5fe2e4.png" data-type="png" data-w="585" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">然后我们可以看到相关的跟踪日志</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.48092485549132946" src="/upload/4f0e1aaa6bad2a194fdcbe9f60b5fca.png" data-type="png" data-w="865" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">同样我们也可以看到微服务之间的依赖关系,这里是通过网关调用了<code style="margin-right: 2px;margin-left: 2px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;background: rgb(248, 245, 236);color: rgb(255, 53, 2);line-height: 1.5;font-size: 90%;padding: 3px 5px;border-radius: 2px;">myservice-consumer-feign</code>微服务,然后通过<code style="margin-right: 2px;margin-left: 2px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;background: rgb(248, 245, 236);color: rgb(255, 53, 2);line-height: 1.5;font-size: 90%;padding: 3px 5px;border-radius: 2px;">myservice-consumer-feign</code>微服务调用了<code style="margin-right: 2px;margin-left: 2px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;background: rgb(248, 245, 236);color: rgb(255, 53, 2);line-height: 1.5;font-size: 90%;padding: 3px 5px;border-radius: 2px;">myservice-provider</code>微服务</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.23980099502487562" src="/upload/a7aef7d76e4c0415aeb497e6b2c36cc5.png" data-type="png" data-w="1005" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 40px;margin-bottom: 20px;font-weight: bold;line-height: 1.5;color: rgb(63, 63, 63);font-size: 120%;"><span style="display: none;"></span>二、搭建ELK<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;"><strong style="color: rgb(255, 53, 2);line-height: 1.5;">1、elasticsearch的安装与配置</strong>,由于之前的文章已经介绍了elasticsearch的单点,集群的安装,head插件的安装。这里不再总结。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;"><strong style="color: rgb(255, 53, 2);line-height: 1.5;">2、kibana的安装</strong>,没什么好说的,解压,运行就可以了</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;"><strong style="color: rgb(255, 53, 2);line-height: 1.5;">3、logstash的安装</strong>,解压即可</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">在config下新建配置文件</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">output&nbsp;{<br>input&nbsp;{<br>&nbsp;&nbsp;tcp&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;port&nbsp;=&gt;&nbsp;4560<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;codec&nbsp;=&gt;&nbsp;json_lines<br>&nbsp;&nbsp;}<br>}<br>&nbsp;<br>output&nbsp;{<br>&nbsp;&nbsp;elasticsearch&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hosts&nbsp;=&gt;&nbsp;[<span style="color: #98c379;line-height: 26px;">"192.168.160.66:9200"</span>,<span style="color: #98c379;line-height: 26px;">"192.168.160.88:9200"</span>,<span style="color: #98c379;line-height: 26px;">"192.168.160.166:9200"</span>]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;index&nbsp;=&gt;&nbsp;<span style="color: #98c379;line-height: 26px;">"applog"</span><br>&nbsp;&nbsp;}<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">其中port为端口号,codec表示通过json格式,elasticsearch.hosts表示elasticsearch的地址,这里是集群。index 为日志存储的elasticsearch索引。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">启动需要调用bin下的logstash命令,通过-f指定配置文件</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;"><strong style="color: rgb(255, 53, 2);line-height: 1.5;">4、使用kibana</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">启动<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI4Njc5NjM1NQ==&amp;mid=2247512709&amp;idx=3&amp;sn=4712185bcf006c61484dbc1095c402ac&amp;chksm=ebd58da9dca204bfc49d071387d9ad655684a39e5f4803ceca2e93333c9239e47a1121c8039f&amp;scene=21#wechat_redirect" textvalue="elasticsearch" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" style="text-decoration: underline;" data-linktype="2">elasticsearch</a>、head、kibana、logstash</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">创建索引applog</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.32748024582967517" src="/upload/2211bb13dd40f55c03520e7d8611256b.png" data-type="png" data-w="1139" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">将applog配置到kibana中,在index pattern中输入我们的applog索引</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.677765843179377" src="/upload/127623ecaaf836accb63c0ed2c29c98c.png" data-type="png" data-w="931" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.46" src="/upload/fad9779137df71e786aa901dca930fc5.png" data-type="png" data-w="1000" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">最后点击create即可</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">点击菜单中的discover即可查看日志</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="1.0330788804071247" src="/upload/9fc7dfd076ac3724c7073b355782fe17.png" data-type="png" data-w="393" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 40px;margin-bottom: 20px;font-weight: bold;line-height: 1.5;color: rgb(63, 63, 63);font-size: 120%;"><span style="display: none;"></span>三、logback配置<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">spring-cloud、logstash都是支持<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI4Njc5NjM1NQ==&amp;mid=2247507987&amp;idx=1&amp;sn=31b68b64ffe830cb6d90870585edc381&amp;chksm=ebd59f3fdca216297576a3017669dbb2998c8e444cf4ce439d53403974ae10ce4131193ffebd&amp;scene=21#wechat_redirect" textvalue="logback" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" style="text-decoration: underline;" data-linktype="2">logback</a>的,因此需要为微服务配置好相应的logback-spring.xml</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(91, 91, 91);border-left-color: rgb(158, 158, 158);background: rgba(158, 158, 158, 0.1);padding-top: 1px;padding-bottom: 1px;margin-top: 20px;margin-bottom: 20px;"> <p style="color: rgb(63, 63, 63);line-height: 1.5;font-size: 16px;margin: 10px;">这里值得注意的是,在spring-boot中,logback-spring.xml的加载在application.yml之前。而我们需要在logback-spring.xml中使用<code style="margin-right: 2px;margin-left: 2px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;background: rgb(248, 245, 236);color: rgb(255, 53, 2);line-height: 1.5;font-size: 90%;padding: 3px 5px;border-radius: 2px;">spring.application.name</code>。因此,我们需要把<code style="margin-right: 2px;margin-left: 2px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;background: rgb(248, 245, 236);color: rgb(255, 53, 2);line-height: 1.5;font-size: 90%;padding: 3px 5px;border-radius: 2px;">spring.application.nam</code>e配置提到bootstrap.yml中。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">加载顺序为bootstrap.yml,logback-spring.xml,application.yml</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">相比普通的logback-spring.xml,我们主要配置这几样东西<code style="margin-right: 2px;margin-left: 2px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;background: rgb(248, 245, 236);color: rgb(255, 53, 2);line-height: 1.5;font-size: 90%;padding: 3px 5px;border-radius: 2px;">spring.application.name</code>,logstash的appender</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">这里提供一个logback-spring.xml的例子</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #61aeee;line-height: 26px;">&lt;?xml&nbsp;version="1.0"&nbsp;encoding="UTF-8"?&gt;</span><br><span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">configuration</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">scan</span>=<span style="color: #98c379;line-height: 26px;">"true"</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">scanPeriod</span>=<span style="color: #98c379;line-height: 26px;">"10&nbsp;seconds"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">springProperty</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">scope</span>=<span style="color: #98c379;line-height: 26px;">"context"</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">name</span>=<span style="color: #98c379;line-height: 26px;">"springAppName"</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #d19a66;line-height: 26px;">source</span>=<span style="color: #98c379;line-height: 26px;">"spring.application.name"</span>&nbsp;/&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">property</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">name</span>=<span style="color: #98c379;line-height: 26px;">"CONSOLE_LOG_PATTERN"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #d19a66;line-height: 26px;">value</span>=<span style="color: #98c379;line-height: 26px;">"%date&nbsp;[%thread]&nbsp;%-5level&nbsp;%logger{36}&nbsp;-&nbsp;%msg%n"</span>&nbsp;/&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">appender</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">name</span>=<span style="color: #98c379;line-height: 26px;">"stdout"</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">class</span>=<span style="color: #98c379;line-height: 26px;">"ch.qos.logback.core.ConsoleAppender"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">withJansi</span>&gt;</span>true<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">withJansi</span>&gt;</span><br>&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">encoder</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">pattern</span>&gt;</span>${CONSOLE_LOG_PATTERN}<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">pattern</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">charset</span>&gt;</span>utf8<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">charset</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">encoder</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">appender</span>&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">appender</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">name</span>=<span style="color: #98c379;line-height: 26px;">"logstash"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #d19a66;line-height: 26px;">class</span>=<span style="color: #98c379;line-height: 26px;">"net.logstash.logback.appender.LogstashTcpSocketAppender"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">destination</span>&gt;</span>192.168.160.66:4560<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">destination</span>&gt;</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">encoder</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">class</span>=<span style="color: #98c379;line-height: 26px;">"net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">providers</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">timestamp</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">timeZone</span>&gt;</span>UTC<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">timeZone</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">timestamp</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">pattern</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">pattern</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"severity":"%level",<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"service":&nbsp;"${springAppName:-}",&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"trace":&nbsp;"%X{X-B3-TraceId:-}",&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"span":&nbsp;"%X{X-B3-SpanId:-}",&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"exportable":&nbsp;"%X{X-Span-Export:-}",&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"pid":&nbsp;"${PID:-}",&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"thread":&nbsp;"%thread",&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"class":&nbsp;"%logger{40}",&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"rest":&nbsp;"%message"&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">pattern</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">pattern</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">providers</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">encoder</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">appender</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">appender</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">name</span>=<span style="color: #98c379;line-height: 26px;">"dailyRollingFileAppender"</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">class</span>=<span style="color: #98c379;line-height: 26px;">"ch.qos.logback.core.rolling.RollingFileAppender"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">File</span>&gt;</span>main.log<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">File</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">rollingPolicy</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">class</span>=<span style="color: #98c379;line-height: 26px;">"ch.qos.logback.core.rolling.TimeBasedRollingPolicy"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">FileNamePattern</span>&gt;</span>main.%d{yyyy-MM-dd}.log<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">FileNamePattern</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">maxHistory</span>&gt;</span>30<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">maxHistory</span>&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">rollingPolicy</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">encoder</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">Pattern</span>&gt;</span>%d{HH:mm:ss.SSS}&nbsp;[%thread]&nbsp;%-5level&nbsp;%logger{35}&nbsp;-&nbsp;%msg&nbsp;%n<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">Pattern</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">encoder</span>&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">filter</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">class</span>=<span style="color: #98c379;line-height: 26px;">"ch.qos.logback.classic.filter.ThresholdFilter"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">level</span>&gt;</span>DEBUG<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">level</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">filter</span>&gt;</span><br>&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">appender</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">springProfile</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">name</span>=<span style="color: #98c379;line-height: 26px;">"!production"</span>&gt;</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">logger</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">name</span>=<span style="color: #98c379;line-height: 26px;">"com.myfee"</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">level</span>=<span style="color: #98c379;line-height: 26px;">"DEBUG"</span>&nbsp;/&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">logger</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">name</span>=<span style="color: #98c379;line-height: 26px;">"org.springframework.web"</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">level</span>=<span style="color: #98c379;line-height: 26px;">"INFO"</span>/&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">root</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">level</span>=<span style="color: #98c379;line-height: 26px;">"info"</span>&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">appender-ref</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">ref</span>=<span style="color: #98c379;line-height: 26px;">"stdout"</span>&nbsp;/&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">appender-ref</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">ref</span>=<span style="color: #98c379;line-height: 26px;">"dailyRollingFileAppender"</span>&nbsp;/&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">appender-ref</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">ref</span>=<span style="color: #98c379;line-height: 26px;">"logstash"</span>&nbsp;/&gt;</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">root</span>&gt;</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">springProfile</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">springProfile</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">name</span>=<span style="color: #98c379;line-height: 26px;">"production"</span>&gt;</span>&nbsp;<br>&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">logger</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">name</span>=<span style="color: #98c379;line-height: 26px;">"com.myfee"</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">level</span>=<span style="color: #98c379;line-height: 26px;">"DEBUG"</span>&nbsp;/&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">logger</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">name</span>=<span style="color: #98c379;line-height: 26px;">"org.springframework.web"</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">level</span>=<span style="color: #98c379;line-height: 26px;">"INFO"</span>/&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">root</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">level</span>=<span style="color: #98c379;line-height: 26px;">"info"</span>&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">appender-ref</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">ref</span>=<span style="color: #98c379;line-height: 26px;">"stdout"</span>&nbsp;/&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">appender-ref</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">ref</span>=<span style="color: #98c379;line-height: 26px;">"dailyRollingFileAppender"</span>&nbsp;/&gt;</span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">appender-ref</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">ref</span>=<span style="color: #98c379;line-height: 26px;">"logstash"</span>&nbsp;/&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">root</span>&gt;</span>&nbsp;<br>&nbsp;<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">springProfile</span>&gt;</span><br><span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">configuration</span>&gt;</span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">我们把message信息配置到了rest字段中。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 40px;margin-bottom: 20px;font-weight: bold;line-height: 1.5;color: rgb(63, 63, 63);font-size: 120%;"><span style="display: none;"></span>三、查询日志<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">启动服务注册中心,网关,需要的微服务,以及sleuth。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">启动elasticsearch,head,kibana,logstash,随便运行一个服务,比如</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.5203426124197003" src="/upload/ef637aeff3fd9765f53cca210b4b50a0.png" data-type="png" data-w="934" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">这里会输出一行日志,内容为<code style="margin-right: 2px;margin-left: 2px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;background: rgb(248, 245, 236);color: rgb(255, 53, 2);line-height: 1.5;font-size: 90%;padding: 3px 5px;border-radius: 2px;">myService-provider userController</code>,通过网关调用</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.3442622950819672" src="/upload/3ab52946346af029413f48f2b600affa.png" data-type="png" data-w="366" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">eclipse控制台输出日志</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.04503582395087001" src="/upload/ddb631ab088519f04dc9184da03dbba3.png" data-type="png" data-w="977" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">在kibana中搜索日志</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.19282511210762332" src="/upload/7a99729a55a4e603b82d8a4ed9c90471.png" data-type="png" data-w="1338" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.6;color: rgb(63, 63, 63);margin-top: 10px;margin-bottom: 10px;">我们看到日志信息在rest字段中。另外,通过trace和span还可以跟踪到整个微服务的调用过程。到此为止,整个日志采集就搭建完成了。系统上线后只需要在elasticsearch中就能搜索到各个服务器上,各个微服务的日志内容了。</p> </section>

自从用完Gradle后,有点嫌弃Maven了!速度贼快!

作者:微信小助手

<p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px 15px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">相信使用Java的同学都用过Maven,这是一个非常经典好用的项目构建工具。但是如果你经常使用Maven,可能会发现Maven有一些地方用的让人不太舒服:</span></p> <p style="margin-bottom: 15px;margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">1. Maven的配置文件是XML格式的,假如你的项目依赖的包比较多,那么XML文件就会变得非常非常长;</span></p> <p style="margin-bottom: 15px;margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">2. XML文件不太灵活,假如你需要在构建过程中添加一些自定义逻辑,搞起来非常麻烦;</span></p> <p style="margin-bottom: 15px;margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">3. Maven非常的稳定,但是相对的就是对新版java支持不足,哪怕就是为了编译java11,也需要更新内置的Maven插件。</span></p> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px 15px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">如果你对Maven的这些缺点也有所感触,准备尝试其他的构建工具,那么你可以试试gradle,这是一个全新的java构建工具,解决了Maven的一些痛点。</span></p> <p><img data-ratio="0.4036697247706422" src="/upload/4d0527b7ad7a361ad8943b8accaed8d7.jpg" data-type="jpeg" data-w="545" style="border-width: 0px;border-style: none;border-color: currentcolor;box-sizing: border-box;display: block;margin: 10px auto;-webkit-tap-highlight-color: transparent;" class="rich_pages wxw-img"></p> <h1 style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 24px;font-variant-numeric: normal;font-variant-east-asian: normal;font-weight: 700;line-height: 32px;margin-top: 28px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;margin-left: 0px;margin-right: 0px;"></h1> <h1 style="margin-top: 28px;font-weight: 700;font-size: 24px;font-variant-numeric: normal;font-variant-east-asian: normal;white-space: normal;border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;text-align: left;-webkit-tap-highlight-color: transparent;margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="border-width: 0px;border-style: none;border-color: currentcolor;-webkit-tap-highlight-color: transparent;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">一、安装Gradle</span></h1> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">最传统的安装方法就是去gradle官网下载二进制包,解压,然后将路径添加到环境变量中。如果你没什么其他需求,可以使用这种安装方式。但是,gradle是一个非常新潮的项目,每隔几个月就会发布一个新版本,这种方式可能跟不上gradle的更新速度。</span></p> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">所以我更加推荐使用包管理器来安装gradle。如果你使用linux系统,那么不必多说。如果你使用Windows系统,我推荐使用scoop包管理器来安装gradle。它安装方便,而且使用SHIM目录来管理环境变量,在各种工具中配置gradle也很方便。</span></p> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">当然,如果你完全不喜欢安装这么多乱七八糟的东西,那也可以使用gradle。gradle提供了一个名为gradle wrapper的工具,可以在没有安装gradle的情况下使用gradle。好吧,其实它就是个脚本文件,当你运行wrapper脚本的时候,如果脚本发现你电脑里没有gradle,就会自动替你下载安装一个。现在甚至还出现了Maven wrapper,也是个脚本文件,可以自动安装Maven。</span></p> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">之前相信一些朋友听说过gradle,然后尝试使用它,结果因为速度太慢,最后放弃了。之前我也因为gradle的速度,放弃了它一段时间。不过现在使用gradle的话会方便很多。gradle官方在中国开设了,CDN,使用gradle wrapper的时候下载速度非常快。可以说现在是一个学习使用gradle的好时候。</span></p> <h1 style="margin-top: 28px;font-weight: 700;font-size: 24px;font-variant-numeric: normal;font-variant-east-asian: normal;white-space: normal;border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;text-align: left;-webkit-tap-highlight-color: transparent;margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;border-width: 0px;border-style: none;border-color: currentcolor;-webkit-tap-highlight-color: transparent;">二、</span>使用gradle wrapper</span></h1> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">这里我使用的IDEA来创建和使用gradle项目。</span></p> <p><img data-ratio="0.6726677577741408" src="/upload/54a1459fb4a652a116c91201760e17eb.jpg" data-type="jpeg" data-w="611" style="border-width: 0px;border-style: none;border-color: currentcolor;box-sizing: border-box;display: block;margin: 10px auto;-webkit-tap-highlight-color: transparent;" class="rich_pages wxw-img"></p> <p style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="color: rgb(34, 34, 34);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-align: left;font-size: 15px;">IDEA默认就会使用gradle wrapper来创建项目,所以无需安装gradle也可以正常运行。这时候项目结构应该类似下图所示,使用Maven的同学应该比较熟悉,因为这和Maven的项目结构几乎完全一致。gradle文件夹和gradlew那几个文件就是gradle wrapper的文件,而.gradle后缀名的文件正是gradle的配置文件,对应于Maven的pom.xml。<br></span></p> <p><img data-ratio="0.7166666666666667" src="/upload/47251a1fb3ec20e135c3bed893c4eb9e.jpg" data-type="jpeg" data-w="480" style="border-width: 0px;border-style: none;border-color: currentcolor;box-sizing: border-box;display: block;margin: 10px auto;-webkit-tap-highlight-color: transparent;" class="rich_pages wxw-img"></p> <p style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="color: rgb(34, 34, 34);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-align: left;font-size: 15px;">gradle wrapper的优点之一就是可以自定义下载的gradle的版本,如果是团队协作的话,这个功能就非常方便,简单设置即可统一团队的构建工具版本。这里我就设定成目前最新的gradle 6.4.默认下载安装的是bin版,仅包含二进制。如果你使用IDEA的话,它会推荐下载all版,包含源代码,这样IDEA就可以分析源代码,提供更加精确的gradle脚本支持。</span></p> <p><img data-ratio="0.2468354430379747" src="/upload/af92c1130d121c3f85de8f932a883b6e.jpg" data-type="jpeg" data-w="948" style="border-width: 0px;border-style: none;border-color: currentcolor;box-sizing: border-box;display: block;margin: 10px auto;-webkit-tap-highlight-color: transparent;" class="rich_pages wxw-img"></p> <h4 style="margin-top: 28px;font-weight: 700;font-variant-numeric: normal;font-variant-east-asian: normal;white-space: normal;border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;text-align: left;-webkit-tap-highlight-color: transparent;margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;border-width: 0px;border-style: none;border-color: currentcolor;-webkit-tap-highlight-color: transparent;">三、</span>依赖管理</span></h4> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">下面来看看gradle的依赖管理功能,这也算是我们使用构建工具的主要目的之一了。这点也是gradle相较maven的优势之一了。相较于maven一大串的XML配置,gradle的依赖项仅需一行。</span></p> <pre style="background: none 0% 0% / auto repeat scroll padding-box border-box rgb(244, 245, 246);border-width: 1px;border-style: solid;border-color: rgb(232, 232, 232);border-radius: 3px;box-shadow: rgba(217, 217, 217, 0.5) 0px 0px 0px 1px inset;color: rgb(153, 153, 153);font-family: Monaco;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;line-height: 1.5;margin-bottom: 1em;margin-top: 1em;overflow-x: auto;padding: 12px 10px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: pre-wrap;"> <section style="margin-left: 0px;margin-right: 0px;"> <code style="border-width: 0px;border-style: none;border-color: currentcolor;font-family: Consolas, Menlo, Courier, monospace;font-size: 1em;-webkit-tap-highlight-color: transparent;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">dependencies {<br style="-webkit-tap-highlight-color: transparent;"> testImplementation 'junit:junit:4.13'<br style="-webkit-tap-highlight-color: transparent;"> implementation 'com.google.code.gson:gson:2.8.6'<br style="-webkit-tap-highlight-color: transparent;">}</span></code> </section></pre> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">这里推荐一下Jetbrains的package search网站,是寻找maven和gradle依赖包的最佳网站,可以非常轻松的搜索和使用依赖项。</span></p> <p><img data-ratio="0.6453125" src="/upload/2163ac0843b274ac952e9c87e77900a1.jpg" data-type="jpeg" data-w="640" style="border-width: 0px;border-style: none;border-color: currentcolor;box-sizing: border-box;display: block;margin: 10px auto;-webkit-tap-highlight-color: transparent;" class="rich_pages wxw-img"></p> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">gradle依赖的粒度控制相较于Maven也更加精细,maven只有compile、provided、test、runtime四种scope,而gradle有以下几种scope:</span></p> <p style="margin-bottom: 15px;margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">1.implementation,默认的scope。implementation的作用域会让依赖在编译和运行时均包含在内,但是不会暴露在类库使用者的编译时。举例,如果我们的类库包含了gson,那么其他人使用我们的类库时,编译时不会出现gson的依赖。</span></p> <p style="margin-bottom: 15px;margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">2.api,和implementation类似,都是编译和运行时都可见的依赖。但是api允许我们将自己类库的依赖暴露给我们类库的使用者。</span></p> <p style="margin-bottom: 15px;margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">3.compileOnly和runtimeOnly,这两种顾名思义,一种只在编译时可见,一种只在运行时可见。而runtimeOnly和Maven的provided比较接近。</span></p> <p style="margin-bottom: 15px;margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">4.testImplementation,这种依赖在测试编译时和运行时可见,类似于Maven的test作用域。</span></p> <p style="margin-bottom: 15px;margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">5.testCompileOnly和testRuntimeOnly,这两种类似于compileOnly和runtimeOnly,但是作用于测试编译时和运行时。</span></p> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">通过简短精悍的依赖配置和多种多样的作用与选择,Gradle可以为我们提供比Maven更加优秀的依赖管理功能。</span></p> <h1 style="margin-top: 28px;font-weight: 700;font-size: 24px;font-variant-numeric: normal;font-variant-east-asian: normal;white-space: normal;border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;text-align: left;-webkit-tap-highlight-color: transparent;margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;border-width: 0px;border-style: none;border-color: currentcolor;-webkit-tap-highlight-color: transparent;">四、</span>gradle的任务和插件</span></h1> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">gradle的配置文件是一个groovy脚本文件,在其中我们可以以编程方式自定义一些构建任务。因为使用了编程方式,所以这带给了我们极大的灵活性和便捷性。打个比方,现在有个需求,要在打包出jar的时候顺便看看jar文件的大小。在gradle中仅需在构建脚本中编写几行代码即可。而在Maven中则需要编写Maven插件,复杂程度完全不在一个水平。</span></p> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">当然,Maven发展到现在,已经存在了大量的插件,提供了各式各样的功能可以使用。但是在灵活性方面还是无法和Gradle相比。而且Gradle也有插件功能,现在发展也十分迅猛,存在了大量非常好用的插件,例如gretty插件。gretty原来是社区插件,后来被官方吸收为官方插件,可以在Tomcat和jetty服务器上运行web项目,比Maven的相关插件功能都强大。</span></p> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">虽然gradle可以非常灵活的编写自定义脚本任务,但是其实一般情况下我们不需要编写构建脚本,利用现有的插件和任务即可完成相关功能。在IDEA里,也可以轻松的查看当前gradle项目中有多少任务,基本任务如build、test等Maven和Gradle都是相通的。</span></p> <p><img data-ratio="0.7587354409317804" src="/upload/2940984b381243778a07d7a04a073c27.jpg" data-type="jpeg" data-w="601" style="border-width: 0px;border-style: none;border-color: currentcolor;box-sizing: border-box;display: block;margin: 10px auto;-webkit-tap-highlight-color: transparent;" class="rich_pages wxw-img"></p> <h1 style="margin-top: 28px;font-weight: 700;font-size: 24px;font-variant-numeric: normal;font-variant-east-asian: normal;white-space: normal;border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;text-align: left;-webkit-tap-highlight-color: transparent;margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;border-width: 0px;border-style: none;border-color: currentcolor;-webkit-tap-highlight-color: transparent;">五、</span>配置镜像</span></h1> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">Maven官方仓库的下载速度非常慢,所以一般我们要配置国内的镜像源。gradle在这方面和Maven完全兼容,因此只需稍微配置一下镜像源,即可使用Maven的镜像。如果你用gradle构建过项目,应该就可以在用户目录的.gradle文件夹下看到gradle的相关配置和缓存。</span></p> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">之前wrapper下载的gradle也存放在该文件夹下,位置是wrapper/dists。</span></p> <p><img data-ratio="0.4399260628465804" src="/upload/9893af1470e4ed0a8eac12b056422b33.jpg" data-type="jpeg" data-w="541" style="border-width: 0px;border-style: none;border-color: currentcolor;box-sizing: border-box;display: block;margin: 10px auto;-webkit-tap-highlight-color: transparent;" class="rich_pages wxw-img"></p> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">而依赖的本地缓存在caches\modules-2\files-2.1文件夹下。目录结构和Maven的本地缓存类似,都是包名+版本号的方式,但是gradle的目录结构最后一层和Maven不同,这导致它们无法共用本地缓存。</span></p> <p><img data-ratio="0.6151260504201681" src="/upload/2a9850c351d7f2673a3aa03c56214638.jpg" data-type="jpeg" data-w="595" style="border-width: 0px;border-style: none;border-color: currentcolor;box-sizing: border-box;display: block;margin: 10px auto;-webkit-tap-highlight-color: transparent;" class="rich_pages wxw-img"></p> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">言归正传,在gradle中配置下载镜像需要在.gradle文件夹中直接新建一个init.gradle初始化脚本,脚本文件内容如下。这样一来,gradle下载镜像的时候就会使用这里配置的镜像源下载,速度会快很多。再加上gradle wrapper在中国设置了CDN,现在使用gradle的速度应该会很快。</span></p> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" mpa-from-tpl="t"> <pre style="margin:0;padding:0;border-radius:none;background:none;"> <section style="border-radius: 4px;font-size: 0.85em;margin: 0px;background: rgb(40, 44, 52);color: rgb(171, 178, 191);display: block;padding: 5.95px;overflow-x: auto;white-space: nowrap;"> <span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(224, 108, 117);background: rgba(0, 0, 0, 0);display: inline;width: 72px;text-decoration: none solid rgb(224, 108, 117);font-weight: 400;font-style: normal;">allprojects</span>&nbsp;{<br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(224, 108, 117);background: rgba(0, 0, 0, 0);display: inline;width: 79px;text-decoration: none solid rgb(224, 108, 117);font-weight: 400;font-style: normal;">repositories</span>&nbsp;{<br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(224, 108, 117);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(224, 108, 117);font-weight: 400;font-style: normal;">maven</span>&nbsp;{<br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 19px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">url</span>&nbsp;<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 287px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"https://maven.aliyun.com/repository/public"</span><br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maven {<br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 19px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">url</span>&nbsp;<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 294px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"https://maven.aliyun.com/repository/jcenter"</span><br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maven {<br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 19px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">url</span>&nbsp;<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 287px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"https://maven.aliyun.com/repository/spring"</span><br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maven {<br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 19px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">url</span>&nbsp;<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 333px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"https://maven.aliyun.com/repository/spring-plugin"</span><br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maven {<br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 19px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">url</span>&nbsp;<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 333px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"https://maven.aliyun.com/repository/gradle-plugin"</span><br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maven {<br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 19px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">url</span>&nbsp;<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 287px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"https://maven.aliyun.com/repository/google"</span><br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maven {<br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 19px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">url</span>&nbsp;<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 320px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"https://maven.aliyun.com/repository/grails-core"</span><br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maven {<br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 19px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">url</span>&nbsp;<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 353px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"https://maven.aliyun.com/repository/apache-snapshots"</span><br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br mpa-from-tpl="t">&nbsp;&nbsp;&nbsp;}<br mpa-from-tpl="t">}</span> </section></pre> </section> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">当然,如果你有代理的话,其实我推荐你直接为gradle设置全局代理。因为gradle脚本实在是太灵活了,有些脚本中可能依赖了github或者其他地方的远程脚本。这时候上面设置的下载镜像源就不管用了。</span></p> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">所以有条件还是干脆直接使用全局代理比较好。设置方式很简单,在.gradle文件夹中新建gradle.properties文件,内容如下。中间几行即是设置代理的配置项。当然其他几行我也建议你设置一下,把gradle运行时的文件编码设置为UTF8,增加跨平台兼容性。</span></p> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" mpa-from-tpl="t"> <pre style="margin:0;padding:0;border-radius:none;background:none;"> <section style="border-radius: 4px;font-size: 0.85em;margin: 0px;background: rgb(40, 44, 52);color: rgb(171, 178, 191);display: block;padding: 5.95px;overflow-x: auto;white-space: nowrap;"> <span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">org.gradle.jvmargs=-Xmx4g -XX:MaxPermSize=<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 19px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">512</span><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 7px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">m</span>&nbsp;-XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 6px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">8</span><br mpa-from-tpl="t">systemProp.http.proxyHost=<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">127.0</span>.<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">0.1</span><br mpa-from-tpl="t">systemProp.http.proxyPort=<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">10800</span><br mpa-from-tpl="t">systemProp.https.proxyHost=<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">127.0</span>.<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">0.1</span><br mpa-from-tpl="t">systemProp.https.proxyPort=<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">10800</span><br mpa-from-tpl="t">systemProp.<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">file</span>.encoding=UTF-<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 7px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">8</span><br mpa-from-tpl="t">org.gradle.warning.<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">mode</span>=<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 19px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">all</span></span> </section></pre> </section> <h1 style="margin-top: 28px;font-weight: 700;font-size: 24px;font-variant-numeric: normal;font-variant-east-asian: normal;white-space: normal;border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;text-align: left;-webkit-tap-highlight-color: transparent;margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;border-width: 0px;border-style: none;border-color: currentcolor;-webkit-tap-highlight-color: transparent;">六、</span>为什么使用gradle?</span></h1> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">看到这里,你应该对gradle有了基本的了解, 也可以将其用于你的项目之中。但是如果你Maven已经非常熟悉了,可能不太愿意使用gradle,因为貌似没有必要。但是既然gradle出现了,就说明有很多人对Maven还是有一定的意见。因此在这里我来总结一下gradle相比maven的优势。</span></p> <p style="border-width: 0px;border-style: none;border-color: currentcolor;color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;font-variant-numeric: normal;font-variant-east-asian: normal;margin: 16px 0px;text-align: left;-webkit-tap-highlight-color: transparent;white-space: normal;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><strong>1.&nbsp;<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;border-width: 0px;border-style: none;border-color: currentcolor;-webkit-tap-highlight-color: transparent;">速度,</span></strong>gradle使用构建缓存、守护进程等方式提高编译速度。结果就是gradle的编译速度要远超maven,平均编译速度比Maven快好几倍,而且项目越大,这个差距就越明显。</span></p> <p><img data-ratio="0.4921875" src="/upload/33108f64c99b77395971d13b4b1e3ddd.jpg" data-type="jpeg" data-w="640" style="border-width: 0px;border-style: none;border-color: currentcolor;box-sizing: border-box;display: block;margin: 10px auto;-webkit-tap-highlight-color: transparent;" class="rich_pages wxw-img"></p> <p style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><strong style="color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;text-align: left;">2. 灵活性,</strong><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(34, 34, 34);text-align: left;">gradle要比Maven灵活太多,虽然有时候灵活并不是一件好事情。但是大部分情况下,灵活一点可以极大的方便我们。Maven死板的XML文件方式做起事情来非常麻烦。很多Maven项目都通过执行外部脚本的方式来完成一些需要灵活性的工作。而在gradle中配置文件就是构建脚本,构建脚本就是编程语言(groovy编程语言),完全可以自给自足,无需外部脚本。</span></span></p> <p style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><strong style="color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;text-align: left;"><br></strong></span></p> <p style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><strong style="color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;font-size: 16px;text-align: left;">3. 简洁性,</strong><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(34, 34, 34);text-align: left;">完成同样的功能,gradle脚本的长度要远远短于maven配置文件的长度。虽然很多人都说XML维护起来不麻烦,但是我觉得,维护一个光是依赖就有几百行的XML文件,不见得就比gradle脚本简单。</span></span></p> <p style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="color: rgb(34, 34, 34);text-align: left;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><br></span></p> <p style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"><span style="color: rgb(34, 34, 34);font-family: &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, &quot;Helvetica Neue&quot;, Arial, sans-serif;text-align: left;font-size: 15px;">也许是因为我上面说的原因,也许有其他原因,不得不承认的一件事情就是gradle作为一个新兴的工具已经有了广泛的应用。spring等项目已经从Maven切换到了gradle。开发安卓程序也只支持gradle了。因此不管是否现在需要将项目从maven切换到gradle,但是至少学习gradle是一件必要的事情。</span></p>