作者:微信小助手
<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: Roboto, Oxygen, Ubuntu, Cantarell, PingFangSC-light, PingFangTC-light, "Open Sans", "Helvetica Neue", sans-serif;"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">互联网时代,面对复杂业务,讲究 <strong style="font-weight: border;color: #0e88eb;">分而治之</strong> 。将一个大的单体系统拆分为若干个微服务,保证每个系统的职责单一,可以垂直深度扩展。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">但是一个个独立的微服务像一座座孤岛,如何将他们串联起来,才能发挥最大价值。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">这时,我们就要提微服务的生态圈。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">那么微服务生态圈都有哪些模块?他们的作用分别是什么?</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <strong style="font-weight: border;color: #0e88eb;">服务的注册、发现</strong> 。生产者启动时,会将自己的信息注册上报,这样调用方只需连接注册中心,根据一定的负载算法,就可以与服务提供方建立连接,从而实现应用间的解耦。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <strong style="font-weight: border;color: #0e88eb;">服务调用</strong> 。通过多种协议(如:HTTP等)实现目标服务的真正调用。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <strong style="font-weight: border;color: #0e88eb;">负载均衡</strong> 。主要是提供多种负载算法,满足不同业务场景下的集群多实例的选择机制 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <strong style="font-weight: border;color: #0e88eb;">服务的稳定性</strong> 。提供了服务熔断、限流、降级 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <strong style="font-weight: border;color: #0e88eb;">分布式配置中心</strong> 。应用的配置项统一管理,修改后能动态生效 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <strong style="font-weight: border;color: #0e88eb;">消息队列</strong> 。非核心逻辑从同步流程抽离,解耦,异步化处理,缩短RT时间 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <strong style="font-weight: border;color: #0e88eb;">网关</strong> 。将一些通用的处理逻辑,如:限流、鉴权、黑白名单、灰度等抽取到一个单独的、前置化系统统一处理。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <strong style="font-weight: border;color: #0e88eb;">监控</strong> 。监控系统的健康状况 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <strong style="font-weight: border;color: #0e88eb;">分布式链路追踪</strong> 。查看接口的调用链路,为性能优化、排查问题提供输入 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <strong style="font-weight: border;color: #0e88eb;">自动化部署</strong> 。持续集成,快速部署应用。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">围绕这些功能模块,<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Spring Cloud Alibaba</code> 为我们提供了微服务化开发的一站式解决方案,我们只需要少量的<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Spring 注解</code> 和 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">yaml配置</code>,便可以快速构建出一套微服务系统。真的是创业者的福音。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">那么这套生态规范都提供了哪些技术框架呢?</strong></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&mid=2247487551&idx=1&sn=18f64ba49f3f0f9d8be9d1fdef8857d9&scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 20px 41.8542px;right: auto;bottom: auto;width: 100%;"><img class="rich_pages wxw-img" data-ratio="0.72125" src="/upload/27c900be6aa67b5ec512dad0c3947e6e.png" data-type="png" data-w="800"></span></a> </figure> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-family: STHeitiSC-Light;color: rgb(14, 136, 235);font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(14, 136, 235);"><a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&mid=2247487551&idx=1&sn=18f64ba49f3f0f9d8be9d1fdef8857d9&scene=21#wechat_redirect" style="color: rgb(14, 136, 235);border-bottom: 0px solid rgb(255, 53, 2);" data-linktype="2">一、Spring Boot(服务基座)</a></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">Spring Boot 是Spring框架的扩展,提供更加 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">丰富的注解</code>,根据 <strong style="font-weight: border;color: #0e88eb;">约定胜于配置</strong> 原则,与市场主流的开源框架打通, 设计了 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Starter</code> 和 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">AutoConfiguration</code> 机制,简化配置流程,通过简单的jar包引入,快速具备组件集成能力。大大提高了程序员的开发效率。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">特点:</strong></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 提供了丰富的注解,不要在XML文件中定义各种繁琐的bean配置 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 内嵌 Web容器,如:Tomcat(默认)、Jetty、Undertow </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 集成了主流开源框架,根据项目依赖自动配置 </section></li> </ul> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 10px;padding-right: 10px;padding-bottom: 10px;line-height: 1.8;border-radius: 0px 0px 10px 10px;color: rgb(14, 136, 235);background: rgb(255, 255, 255);box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;">基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能。</p> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;">项目地址:https://github.com/YunaiV/ruoyi-vue-pro</p> </blockquote> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-family: STHeitiSC-Light;color: rgb(14, 136, 235);font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(14, 136, 235);"><a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&mid=2247487551&idx=1&sn=18f64ba49f3f0f9d8be9d1fdef8857d9&scene=21#wechat_redirect" style="color: rgb(14, 136, 235);border-bottom: 0px solid rgb(255, 53, 2);" data-linktype="2">二、Nacos(注册中心、分布式配置中心)</a></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">Nacos 是阿里巴巴的开源的项目,全称 Naming Configuration Service ,专注于服务发现和配置管理领域。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。功能齐全,可以替换之前的 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Spring Cloud Netflix Eureka</code>、<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Spring Cloud Config</code>、<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Spring Cloud Bus</code>,野心巨大。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">客户端语言方面目前支持 Java,go 、python、 C# 和 C++等主流语言</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 10px;padding-right: 10px;padding-bottom: 10px;line-height: 1.8;border-radius: 0px 0px 10px 10px;color: rgb(14, 136, 235);background: rgb(255, 255, 255);box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;">开源地址:https://github.com/alibaba/nacos</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">Nacos 有一个控制台,可以帮助用户管理服务,监控服务状态、应用的配置管理。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">集群化部署:</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">由于 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Nacos</code> 是单节点,无论做为<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">注册中心</code>还是<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">分布式配置中心</code>,一旦服务器挂了,作为底层服务引发的麻烦还是非常大的。如何保证其高可用?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">Nacos 官方提供的集群部署架构图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&mid=2247487551&idx=1&sn=18f64ba49f3f0f9d8be9d1fdef8857d9&scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 20px 41.8542px;right: auto;bottom: auto;width: 100%;"><img class="rich_pages wxw-img" data-ratio="0.5514184397163121" src="/upload/6565dd3f419387570db898c1151d2f7c.jpg" data-type="jpeg" data-w="564" style="border-radius: 0px 0px 5px 5px;display: block;margin: 0px;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"></span></a> </figure> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 10px;padding-right: 10px;padding-bottom: 10px;line-height: 1.8;border-radius: 0px 0px 10px 10px;color: rgb(14, 136, 235);background: rgb(255, 255, 255);box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;">https://nacos.io/zh-cn/docs/cluster-mode-quick-start.html</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">在nacos的解压目录<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">nacos/conf</code>目录下,有配置文件<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">cluster.conf</code>,每行配置成 ip:port。(一般配置3个或3个以上节点)</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("https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwAShlgL0iceQMrGn7Kxwsu99s6EJ7cc6Zm9hp4LZKf9aCfTEoBNOTn2qhIoeibXJS2En4kia8nyy4pG79/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><br>> 基于微服务的思想,构建在 B2C 电商场景下的项目实战。核心技术栈,是 Spring Boot + Dubbo 。未来,会重构成 Spring Cloud Alibaba 。<br>><br>> 项目地址:<https:<span style="color: #57A64A;font-style: italic;line-height: 26px;">//github.com/YunaiV/onemall></span><br><br># ip:port<br><span style="color: #B8D7A3;line-height: 26px;">200.8</span><span style="color: #B8D7A3;line-height: 26px;">.9</span><span style="color: #B8D7A3;line-height: 26px;">.16</span>:<span style="color: #B8D7A3;line-height: 26px;">8848</span><br><span style="color: #B8D7A3;line-height: 26px;">200.8</span><span style="color: #B8D7A3;line-height: 26px;">.9</span><span style="color: #B8D7A3;line-height: 26px;">.17</span>:<span style="color: #B8D7A3;line-height: 26px;">8848</span><br><span style="color: #B8D7A3;line-height: 26px;">200.8</span><span style="color: #B8D7A3;line-height: 26px;">.9</span><span style="color: #B8D7A3;line-height: 26px;">.18</span>:<span style="color: #B8D7A3;line-height: 26px;">8848</span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">这样保证客户端只需要写一次,由 Leader节点将数据同步到其他节点,保证各个节点的数据一致性</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">对于上层的SLB,我们可以采用 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Nginx</code> 或者 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">OpenResty</code>,在 upstream 模块里配置 Nacos 的集群IP 地址列表,实现负载均衡功能。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">另外,借助Nginx的心跳检测,当某台 Nacos 服务挂掉后,SLB 会自动屏蔽,将流量切换到其他 Nacos 实例。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">当然 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">OpenResty</code> 也可能成为单点故障,为了保证高可用,我们需要借助 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Keepalived</code></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&mid=2247487551&idx=1&sn=18f64ba49f3f0f9d8be9d1fdef8857d9&scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 20px 41.8542px;right: auto;bottom: auto;width: 100%;"><img class="rich_pages wxw-img" data-ratio="0.7324074074074074" src="/upload/e14026aad671599c33944f93f78d044b.jpg" data-type="jpeg" data-w="1080" style="border-radius: 0px 0px 5px 5px;display: block;margin: 0px;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"></span></a> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">客户端请求 VIP,然后请求打到了 OpenResty,由 OpenResty 转发给具体的某个 Nacos 节点。</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 10px;padding-right: 10px;padding-bottom: 10px;line-height: 1.8;border-radius: 0px 0px 10px 10px;color: rgb(14, 136, 235);background: rgb(255, 255, 255);box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;">OpenResty 只有一个节点提供服务,另一个暂停状态,如果 master 节点宕机,那 backup 接替继续工作。从而解决了单点故障问题。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">Keepalived 作为一种高性能的服务器高可用或热备解决方案,用来防止服务器单点故障的发生。市面资料很多,下文链接是《Keepalived+Nginx部署方案》具体操作步骤</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 10px;padding-right: 10px;padding-bottom: 10px;line-height: 1.8;border-radius: 0px 0px 10px 10px;color: rgb(14, 136, 235);background: rgb(255, 255, 255);box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;">https://help.fanruan.com/finereport/doc-view-2905.html</p> </blockquote> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-family: STHeitiSC-Light;color: rgb(14, 136, 235);font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(14, 136, 235);"><a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&mid=2247487551&idx=1&sn=18f64ba49f3f0f9d8be9d1fdef8857d9&scene=21#wechat_redirect" style="color: rgb(14, 136, 235);border-bottom: 0px solid rgb(255, 53, 2);" data-linktype="2">三、RestTemplate + Ribbon (远程调用)</a></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">Spring Cloud Ribbon 基于 Netflix Ribbon 封装的负载均衡框架。内部集成了多种负载算法,如:随机、轮询等。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">与注册中心打通,能自动获取服务提供者的地址列表。结合自身的负载算法,选择一个目标实例发起服务调用。</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 10px;padding-right: 10px;padding-bottom: 10px;line-height: 1.8;border-radius: 0px 0px 10px 10px;color: rgb(14, 136, 235);background: rgb(255, 255, 255);box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;">Ribbon 也提供了扩展接口,支持自定义负载均衡算法。</p> </blockquote> <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("https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwAShlgL0iceQMrGn7Kxwsu99s6EJ7cc6Zm9hp4LZKf9aCfTEoBNOTn2qhIoeibXJS2En4kia8nyy4pG79/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><span style="color: #569CD6;line-height: 26px;">public</span> <span style="color: #B8D7A3;line-height: 26px;"><span style="color: #569CD6;line-height: 26px;">class</span> <span style="color: #DCDCDC;line-height: 26px;">CustomRule</span> <span style="color: #569CD6;line-height: 26px;">extends</span> <span style="color: #DCDCDC;line-height: 26px;">AbstractLoadBalancerRule</span> </span>{<br> <span style="color: #569CD6;line-height: 26px;">private</span> AtomicInteger count = <span style="color: #569CD6;line-height: 26px;">new</span> AtomicInteger(<span style="color: #B8D7A3;line-height: 26px;">0</span>);<br> <span style="color: #9B9B9B;line-height: 26px;">@Override</span><br> <span style="line-height: 26px;"><span style="color: #569CD6;line-height: 26px;">public</span> Server <span style="line-height: 26px;">choose</span><span style="line-height: 26px;">(Object key)</span> </span>{ <br> <span style="color: #569CD6;line-height: 26px;">return</span> choose(getLoadBalancer(), key);<br> }<br><br> <span style="line-height: 26px;"><span style="color: #569CD6;line-height: 26px;">private</span> Server <span style="line-height: 26px;">choose</span><span style="line-height: 26px;">(ILoadBalancer loadBalancer, Object key)</span> </span>{<br> List<Server> allServers = loadBalancer.getAllServers(); <br> <span style="color: #569CD6;line-height: 26px;">int</span> requestNumber = count.incrementAndGet(); <br> <span style="color: #569CD6;line-height: 26px;">if</span> (requestNumber >= Integer.MAX_VALUE) { <br> count = <span style="color: #569CD6;line-height: 26px;">new</span> AtomicInteger(<span style="color: #B8D7A3;line-height: 26px;">0</span>); <br> }<br> <span style="color: #569CD6;line-height: 26px;">if</span> (<span style="color: #569CD6;line-height: 26px;">null</span> != allServers) {<br> <span style="color: #569CD6;line-height: 26px;">int</span> size = allServers.size();<br> <span style="color: #569CD6;line-height: 26px;">if</span> (size > <span style="color: #B8D7A3;line-height: 26px;">0</span>) {<br> <span style="color: #569CD6;line-height: 26px;">int</span> index = requestNumber % size; <br> Server server = allServers.get(index);<br> <span style="color: #569CD6;line-height: 26px;">if</span> (<span style="color: #569CD6;line-height: 26px;">null</span> == server || !server.isAlive()) { <br> <span style="color: #569CD6;line-height: 26px;">return</span> <span style="color: #569CD6;line-height: 26px;">null</span>;<br> }<br> <span style="color: #569CD6;line-height: 26px;">return</span> server;<br> }<br> }<br> <span style="color: #569CD6;line-height: 26px;">return</span> <span style="color: #569CD6;line-height: 26px;">null</span>;<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">缺点:</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">调用方每次发起远程服务调用时,都需要填写<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">远程目标地址</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;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwAShlgL0iceQMrGn7Kxwsu99s6EJ7cc6Zm9hp4LZKf9aCfTEoBNOTn2qhIoeibXJS2En4kia8nyy4pG79/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><span style="color: #57A64A;font-style: italic;line-height: 26px;">// 注册到Nacos的应用名称</span><br><span style="color: #569CD6;line-height: 26px;">private</span> <span style="color: #569CD6;line-height: 26px;">final</span> String SERVER_URL = <span style="color: #D69D85;line-height: 26px;">"http://nacos-provider-demo"</span>; <br><span style="color: #9B9B9B;line-height: 26px;">@Resource</span><br><span style="color: #569CD6;line-height: 26px;">private</span> RestTemplate restTemplate;<br><br><span style="color: #9B9B9B;line-height: 26px;">@RequestMapping</span>(<span style="color: #D69D85;line-height: 26px;">"/hello"</span>) <br><span style="line-height: 26px;"><span style="color: #569CD6;line-height: 26px;">public</span> String <span style="line-height: 26px;">hello</span><span style="line-height: 26px;">()</span> </span>{<br> <span style="color: #57A64A;font-style: italic;line-height: 26px;">// 远程服务调用</span><br> <span style="color: #569CD6;line-height: 26px;">return</span> restTemplate.getForObject(SERVER_URL + <span style="color: #D69D85;line-height: 26px;">"/hello"</span>, String<span style="color: #B8D7A3;line-height: 26px;">.<span style="color: #569CD6;line-height: 26px;">class</span>)</span>;<br>}<br></code></pre> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-family: STHeitiSC-Light;color: rgb(14, 136, 235);font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(14, 136, 235);"><a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&mid=2247487551&idx=1&sn=18f64ba49f3f0f9d8be9d1fdef8857d9&scene=21#wechat_redirect" style="color: rgb(14, 136, 235);border-bottom: 0px solid rgb(255, 53, 2);" data-linktype="2">四、OpenFeign(远程调用)</a></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">RestTemplate + Ribbon 每次发起远程服务调用时,都需要填写<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">远程目标地址</code>,还要配置各种参数,非常麻烦。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">Feign 是一个轻量级的 Restful HTTP 客户端,<strong style="font-weight: border;color: #0e88eb;">内嵌了 Ribbon 作为客户端的负载均衡</strong> 。面向接口编程,使用时只需要定义一个接口并加上<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">@FeignClient</code>注解,非常方便。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">OpenFeign 是 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Feign</code> 的增强版。对 Feign 进一步封装,支持 Spring MVC 的标准注解和HttpMessageConverts</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">依赖包:</strong></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("https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwAShlgL0iceQMrGn7Kxwsu99s6EJ7cc6Zm9hp4LZKf9aCfTEoBNOTn2qhIoeibXJS2En4kia8nyy4pG79/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><dependency><br> <groupId>org.springframework.cloud</groupId><br> <artifactId>spring-cloud-starter-openfeign</artifactId><br></dependency><br><span style="color: #9B9B9B;line-height: 26px;">@FeignClient</span>(value = <span style="color: #D69D85;line-height: 26px;">"${provider.name}"</span>) <br><span style="color: #569CD6;line-height: 26px;">public</span> <span style="color: #B8D7A3;line-height: 26px;"><span style="color: #569CD6;line-height: 26px;">interface</span> <span style="color: #DCDCDC;line-height: 26px;">OrderService</span> </span>{<br><br> <span style="color: #57A64A;font-style: italic;line-height: 26px;">// 调用服务提供者的 /create_order 接口</span><br> <span style="color: #9B9B9B;line-height: 26px;">@RequestMapping</span>(value = <span style="color: #D69D85;line-height: 26px;">"/create_order"</span>,method = RequestMethod.GET) <br> <span style="line-height: 26px;"><span style="color: #569CD6;line-height: 26px;">public</span> String <span style="line-height: 26px;">createOrder</span><span style="line-height: 26px;">()</span></span>;<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">其中,<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">@FeignClient(value = "${provider.name}")</code> 定义了服务提供方的工程名,底层自动打通了注册中心,会拿到 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">artifactId</code> 对应的IP列表,根据一定的负载均衡算法,可以将请求打到目标服务器上。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">OpenFeign 默认等待接口返回数据的时间是 1 秒,超过这个时间就会报错。如果想调整这个时间,可以修改配置项 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">feign.client.config.default.readTimeout</code></p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-family: STHeitiSC-Light;color: rgb(14, 136, 235);font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(14, 136, 235);"><a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&mid=2247487551&idx=1&sn=18f64ba49f3f0f9d8be9d1fdef8857d9&scene=21#wechat_redirect" style="color: rgb(14, 136, 235);border-bottom: 0px solid rgb(255, 53, 2);" data-linktype="2">五、Dubbo Spring Cloud(远程调用)</a></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">RestTemplate + Ribbon</code> 和 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">OpenFeign</code> 都是基于HTTP协议调用远程接口。而 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Dubbo Spring Cloud</code> 是基于 TCP 协议来调用远程接口。相比 HTTP 的大量的请求头,TCP 更轻量级。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">Dubbo Spring Cloud = Spring Cloud + Dubbo</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">特性:</strong></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 支持多种注册中心,用于服务的注册、发现 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 内置多种负载均衡策略 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 服务粒度是 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">面向接口</code>,支持 TCP 轻量级协议 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 容易扩展,采用 微内核 + 插件 的设计原则,扩展点更强 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">依赖包:</strong></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("https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwAShlgL0iceQMrGn7Kxwsu99s6EJ7cc6Zm9hp4LZKf9aCfTEoBNOTn2qhIoeibXJS2En4kia8nyy4pG79/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><span style="color: #9B9B9B;line-height: 26px;"><<span style="color: #569CD6;line-height: 26px;">dependency</span>></span><br> <span style="color: #9B9B9B;line-height: 26px;"><<span style="color: #569CD6;line-height: 26px;">groupId</span>></span>com.alibaba.cloud<span style="color: #9B9B9B;line-height: 26px;"></<span style="color: #569CD6;line-height: 26px;">groupId</span>></span><br> <span style="color: #9B9B9B;line-height: 26px;"><<span style="color: #569CD6;line-height: 26px;">artifactId</span>></span>spring-cloud-starter-dubbo<span style="color: #9B9B9B;line-height: 26px;"></<span style="color: #569CD6;line-height: 26px;">artifactId</span>></span><br><span style="color: #9B9B9B;line-height: 26px;"></<span style="color: #569CD6;line-height: 26px;">dependency</span>></span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">注意:虽然是将 Dubbo 集成到了 Spring Cloud,增加了一些 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">注解</code> 和 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">yaml</code> 配置项,开发更方便,但大部分调用玩法还是遵守 Dubbo 框架那一套。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">几个重要的配置项:</strong></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> dubbo.scan.base-packages # dubbo 服务扫描基准包,上报注册服务 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> dubbo.protocol.name: dubbo # 支持的协议 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> dubbo.protocol.port: -1 # dubbo 协议端口( -1 表示自增端口,从 20880 开始) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> dubbo.registry.address # 注册中心地址 </section></li> </ul> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-family: STHeitiSC-Light;color: rgb(14, 136, 235);font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(14, 136, 235);"><a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&mid=2247487551&idx=1&sn=18f64ba49f3f0f9d8be9d1fdef8857d9&scene=21#wechat_redirect" style="color: rgb(14, 136, 235);border-bottom: 0px solid rgb(255, 53, 2);" data-linktype="2">六、Spring Cloud Gateway(网关)</a></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">分布式时代,一个复杂的系统被拆分为若干个微服务系统,每个系统都配置独立的域名肯定不合适。为了解决这个问题,网关便诞生了。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">网关充当反向代理的角色,作为流量的第一入口,承载了很多基础的、公共的模块功能,如:流控、鉴权、监控、路由转发等。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&mid=2247487551&idx=1&sn=18f64ba49f3f0f9d8be9d1fdef8857d9&scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 20px 41.8542px;right: auto;bottom: auto;width: 100%;"><img class="rich_pages wxw-img" data-ratio="0.5592592592592592" src="/upload/875e1700995b4dba06d4271038f07468.jpg" data-type="jpeg" data-w="1080" style="border-radius: 0px 0px 5px 5px;display: block;margin: 0px;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"></span></a> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">Spring Cloud 生态早期的网关是 Netflix 公司的Zuul,后来Zuul社区停止了维护。官方后来推出了 Spring Cloud Gateway,<strong style="font-weight: border;color: #0e88eb;">其底层是基于 WebFlux 框架</strong> ,而WebFlux框架的底层采用高性能通讯框架 Netty,性能是 Zuul 的 1.6 倍。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">核心组件:</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">1、路由。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">内部主要是负责转发规则。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">2、断言(Predicate)</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">如果返回为true,当前路由才有效,才会路由到具体的服务。官方提供了很多<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">内置路由断言</code>,如果满足不了你的诉求,也可以<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">自定义路由断言工厂</code>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">所有的路由断言工厂都是继承自 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">AbstractRoutePredicateFactory</code>,自定义类的命名也有固定规则,<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">“配置名”+RoutePredicateFactory</code>。这样,在yaml配置时,只需要写<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">前面定义的配置名</code>即可。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">3、过滤器(Filter)</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">主要是请求、响应之间增加一些自定义的逻辑。按作用范围分为:全局和局部。全局是作用于所有的路由;而局部只是作用于某一个路由。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">跟上面的断言类似,除了官方提供的过滤器,也支持自定义。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">局部过滤器</strong> :继承自 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">AbstractGatewayFilterFactory</code>,自定义类的命名也有固定规则,<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">“配置名”+GatewayFilterFactory</code>。这样,在yaml配置时,只需要写<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">前面定义的配置名</code>即可。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">全局过滤器</strong> :实现<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">GlobalFilter</code>,<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Ordered</code> 两个接口,实现逻辑跟上面的局部过滤器类似。这里就不展开了。其中的 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Ordered</code> 接口主要是负责优先级,数值越小,优先级越高。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">依赖包:</strong></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("https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwAShlgL0iceQMrGn7Kxwsu99s6EJ7cc6Zm9hp4LZKf9aCfTEoBNOTn2qhIoeibXJS2En4kia8nyy4pG79/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><span style="color: #9B9B9B;line-height: 26px;"><<span style="color: #569CD6;line-height: 26px;">dependency</span>></span><br> <span style="color: #9B9B9B;line-height: 26px;"><<span style="color: #569CD6;line-height: 26px;">groupId</span>></span>org.springframework.cloud<span style="color: #9B9B9B;line-height: 26px;"></<span style="color: #569CD6;line-height: 26px;">groupId</span>></span><br> <span style="color: #9B9B9B;line-height: 26px;"><<span style="color: #569CD6;line-height: 26px;">artifactId</span>></span>spring-cloud-starter-gateway<span style="color: #9B9B9B;line-height: 26px;"></<span style="color: #569CD6;line-height: 26px;">artifactId</span>></span><br><span style="color: #9B9B9B;line-height: 26px;"></<span style="color: #569CD6;line-height: 26px;">dependency</span>></span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">yaml 的配置示例:</strong></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("https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwAShlgL0iceQMrGn7Kxwsu99s6EJ7cc6Zm9hp4LZKf9aCfTEoBNOTn2qhIoeibXJS2En4kia8nyy4pG79/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><span style="color: #9CDCFE;line-height: 26px;">spring:</span><br> <span style="color: #9CDCFE;line-height: 26px;">cloud:</span><br> <span style="color: #9CDCFE;line-height: 26px;">gateway:</span><br> <span style="color: #9CDCFE;line-height: 26px;">routes:</span> <span style="color: #57A64A;font-style: italic;line-height: 26px;">#路由,可配置多个</span><br> <span style="color: #D7BA7D;line-height: 26px;">-</span> <span style="color: #9CDCFE;line-height: 26px;">id:</span> <span style="color: #D69D85;line-height: 26px;">user_route</span> <span style="color: #57A64A;font-style: italic;line-height: 26px;"># 路由id 唯一即可,默认是UUID</span><br> <span style="color: #9CDCFE;line-height: 26px;">uri:</span> <span style="color: #D69D85;line-height: 26px;">lb://user-server-sample</span> <span style="color: #57A64A;font-style: italic;line-height: 26px;"># 匹配成功后提供的服务的地址</span><br> <span style="color: #9CDCFE;line-height: 26px;">order:</span> <span style="color: #B8D7A3;line-height: 26px;">1</span> <span style="color: #57A64A;font-style: italic;line-height: 26px;"># 路由优先级,数值越小优先级越高,默认0</span><br> <span style="color: #9CDCFE;line-height: 26px;">predicates:</span><br> <span style="color: #D7BA7D;line-height: 26px;">-</span> <span style="color: #D69D85;line-height: 26px;">Path=/user/**</span> <span style="color: #57A64A;font-style: italic;line-height: 26px;"># 断言,路径匹配进行路由</span><br> <span style="color: #57A64A;font-style: italic;line-height: 26px;"># - User=0, 1000 # 自定义路由断言工厂 只允许查询id为0 - 1000之间的用户</span><br> <span style="color: #57A64A;font-style: italic;line-height: 26px;"># - Method=POST # 表示需要POST方式请求</span><br> <span style="color: #57A64A;font-style: italic;line-height: 26px;"># - Query=id, \d+ # 参数名id,正则表达式为\d+(一个或多个数字)</span><br> &nb
作者:微信小助手
<p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.14106583072100312" src="/upload/a83f0db3ab48535b968a42f5fe078c47.png" data-type="gif" data-w="638" style=""></p> <p><strong><span style="font-size: 15px;color: rgb(255, 106, 0);"><br mpa-from-tpl="t"></span></strong><br></p> <section data-mpa-template="t" mpa-from-tpl="t"> <section data-role="title" data-tools="135编辑器" data-id="106625" mpa-from-tpl="t"> <section style="text-align: center;margin: 10px auto;" mpa-from-tpl="t"> <section style="display: inline-block;" mpa-from-tpl="t"> <section style="display: flex;justify-content: center;align-items: flex-end;padding-right: 7px;padding-left: 7px;" mpa-from-tpl="t"> <section style="font-size: 28px;letter-spacing: 1.5px;color: #ffffff;font-style: italic;text-shadow: 1px 1px 0px #ff5532;line-height: 25px;" mpa-from-tpl="t"> <strong mpa-from-tpl="t">01</strong> <strong data-original-title="" title="" data-num="3" mpa-from-tpl="t"></strong> </section> <section data-brushtype="text" style="font-size: 16px;letter-spacing: 1.5px;color: #f2622e;margin-left: 15px;" hm_fix="343:395" mpa-from-tpl="t"> <p style="line-height: normal;"><strong mpa-from-tpl="t">前言</strong></p> </section> </section> <section style="width: 100%;height: 6px;background-color: rgba(245, 224, 179, 0.8);margin-top: 6px;opacity: 0.51;" data-width="100%" data-role="list" mpa-from-tpl="t"> <p style="line-height: 0.5em;"><span style="font-size: 14px;"><em><span style="color: #a5a5a5;">Aliware</span></em></span></p> </section> </section> </section> </section> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">相较于大家熟练使用的 MVC 分层架构,领域驱动设计更适用于复杂业务系统和需要持续迭代的软件系统的架构模型。关于领域驱动设计的概念及优势,可以参考的文献非常多,大多数的同学都看过相关的书籍,所以本文不讨论领域驱动概念层面的东西,而是试图从编程实践的层面,对领域驱动开发做一些简单的介绍。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br style="box-sizing: border-box;">加入阿里健康之后,我所在的团队也在积极推进领域驱动设计的应用,相关同学也曾给出优秀的脚手架代码,但目前看起来落地情况并不太理想,个人浅见,造成这种结果主要有四个原因。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <ol class="list-paddingleft-1"> <li style="font-size: 15px;color: rgb(62, 62, 62);"> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">大家更熟悉 MVC 的编程模式,需要快速实现某个功能的时候,往往倾向于使用较为稳妥、熟悉的方式。</span> </section><p><br></p></li> <li> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">大家对领域驱动编程应该怎么编写并没有一个统一的认知(</span> <span style="font-size: 15px;color: rgb(62, 62, 62);">Axon Framework[1]</span> <span style="font-size: 15px;color: rgb(62, 62, 62);"> 对领域驱动设计实现的非常好,但它太“重”了)。</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(62, 62, 62);"> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">DDD 落地本身就比较难,往往需要事件驱动和 Event Store 来完美实现,而这二者是我们不常用的。</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(62, 62, 62);"> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">领域驱动设计是面向复杂系统的,业务发展初期看上去都比较简单,一上来就搞领域驱动设计有过度设计之嫌。这也是领域驱动设计常常在系统不得不重构的是时候才被拿出来讨论的原因。</span> </section></li> </ol> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">笔者曾在研发过程中研究、实践过领域驱动编程,对领域驱动框架 </span> <span style="font-size: 15px;color: rgb(62, 62, 62);">Axon Framework</span> <span style="font-size: 15px;color: rgb(62, 62, 62);"> 也做了深入的了解,(也许是因为业务场景相对简单)当时落地效果还不错。抛却架构师的视角,从一线研发同学的角度来看,基于领域驱动编程的核心优势在于:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <ol class="list-paddingleft-1"> <li style="font-size: 15px;color: rgb(62, 62, 62);"> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">实施面向对象的编程模式,进而实现高内聚、低耦合。</span> </section><p><br></p></li> <li style="font-size: 15px;color: rgb(62, 62, 62);"> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">在复杂业务系统的迭代过程中,保证代码结构不会无限制地变得混乱,因此保证系统可持续维护。</span> </section></li> </ol> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">领域驱动开发最重要的当然是正确地进行领域拆解,这个拆解工作可以在理论的指导下,结合设计者对业务的深入分析和充分理解进行。本文假定开发前已经进行了领域划分,侧重于研究编码阶段具体如何实践才能体现领域驱动的优势。</span> <strong><span style="font-size: 15px;color: rgb(255, 106, 0);"></span></strong> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br mpa-from-tpl="t"></span> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <section data-role="title" data-tools="135编辑器" data-id="106625" mpa-from-tpl="t"> <section style="text-align: center;margin: 10px auto;" mpa-from-tpl="t"> <section style="display: inline-block;" mpa-from-tpl="t"> <section style="display: flex;justify-content: center;align-items: flex-end;padding-right: 7px;padding-left: 7px;" mpa-from-tpl="t"> <section style="font-size: 28px;letter-spacing: 1.5px;color: #ffffff;font-style: italic;text-shadow: 1px 1px 0px #ff5532;line-height: 25px;" mpa-from-tpl="t"> <strong mpa-from-tpl="t">02</strong> <strong data-original-title="" title="" data-num="3" mpa-from-tpl="t"></strong> </section> <section data-brushtype="text" style="font-size: 16px;letter-spacing: 1.5px;color: #f2622e;margin-left: 15px;" hm_fix="343:395" mpa-from-tpl="t"> <p style="line-height: normal;"><strong mpa-from-tpl="t"><strong>保险领域知识简介</strong></strong></p> </section> </section> <section style="width: 100%;height: 6px;background-color: rgba(245, 224, 179, 0.8);margin-top: 6px;opacity: 0.51;" data-width="100%" data-role="list" mpa-from-tpl="t"> <p style="line-height: 0.5em;"><span style="font-size: 14px;"><em><span style="color: #a5a5a5;">Aliware</span></em></span></p> </section> </section> </section> </section> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">以保险业务为例来进行编程实践,一个高度抽象的保险领域划分如图所示。通过用例分析,我们把整个业务划分成产品域、承保、核保、理赔等多个领域(Bounded-Context),每个领域又可以根据业务发展情况拆分子域。当然,完备保险业务要比图中展现的复杂太多,这里我们不作为业务知识介绍的篇章,只是为了方便后续的代码实践。</span> </section> <p><img class="rich_pages wxw-img" data-backh="455" data-backw="579" data-ratio="0.7873900293255132" src="/upload/b02b908a18e860c86f9315105a41066e.png" data-type="png" data-w="1364" style="box-sizing: border-box;display: block;margin: 20px auto;cursor: zoom-in;height: auto;width: 100%;"></p> <h2 style="line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(255, 106, 0);"><br mpa-from-tpl="t"></span></strong></h2> <section data-mpa-template="t" mpa-from-tpl="t"> <section data-role="title" data-tools="135编辑器" data-id="106625" mpa-from-tpl="t"> <section style="text-align: center;margin: 10px auto;" mpa-from-tpl="t"> <section style="display: inline-block;" mpa-from-tpl="t"> <section style="display: flex;justify-content: center;align-items: flex-end;padding-right: 7px;padding-left: 7px;" mpa-from-tpl="t"> <section style="font-size: 28px;letter-spacing: 1.5px;color: #ffffff;font-style: italic;text-shadow: 1px 1px 0px #ff5532;line-height: 25px;" mpa-from-tpl="t"> <strong mpa-from-tpl="t">03</strong> <strong data-original-title="" title="" data-num="3" mpa-from-tpl="t"></strong> </section> <section data-brushtype="text" style="font-size: 16px;letter-spacing: 1.5px;color: rgb(242, 98, 46);margin-left: 15px;" hm_fix="343:395" mpa-from-tpl="t"> <p style="line-height: normal;"><strong mpa-from-tpl="t"><strong>领域驱动开发的代码结构</strong></strong></p> </section> </section> <section style="width: 100%;height: 6px;background-color: rgba(245, 224, 179, 0.8);margin-top: 6px;opacity: 0.51;" data-width="100%" data-role="list" mpa-from-tpl="t"> <p style="line-height: 0.5em;"><span style="font-size: 14px;"><em><span style="color: #a5a5a5;">Aliware</span></em></span></p> </section> </section> </section> </section> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <section data-mpa-template="t" mpa-from-tpl="t"> <section data-role="title" data-tools="135编辑器" data-id="107115" mpa-from-tpl="t"> <section style="text-align: left;margin: 10px auto;" mpa-from-tpl="t"> <section style="display: inline-block;" mpa-from-tpl="t"> <section style="border-width: 1px;border-style: solid;border-color: rgb(255, 106, 0);padding: 4px;" mpa-from-tpl="t"> <section style="width: 30px;height: 30px;background-color: rgb(255, 106, 0);" mpa-from-tpl="t"> <section style="font-size: 16px;letter-spacing: 1.5px;color: #ff6a00fff;line-height: 30px;" hm_fix="320:270" mpa-from-tpl="t"> <span style="color:#ffffff;"><strong mpa-from-tpl="t">01</strong></span> </section> </section> <section style="display: flex;justify-content: flex-end;align-items: flex-end;margin-top: -11px;" mpa-from-tpl="t"> <section style="width: 0px;height: 1px;border-bottom: 11px solid rgb(255, 106, 0);border-left: 11px solid transparent;margin-right: -8px;overflow: hidden;" mpa-from-tpl="t"> <br mpa-from-tpl="t"> </section> <section style="line-height: 0.588235em;color: rgb(255, 106, 0);text-indent: 0em;font-family: 微软雅黑;" mpa-from-tpl="t"> <section style="width: 0px;height: 1px;border-bottom: 8px solid rgb(255, 205, 98);border-left: 8px solid transparent;overflow: hidden;" mpa-from-tpl="t"> <br mpa-from-tpl="t"> </section> </section> </section> </section> </section> </section> <p style="vertical-align: inherit;color: rgb(255, 106, 0);text-indent: 0em;font-family: 微软雅黑;"><span style="color: rgb(255, 106, 0);"><strong mpa-from-tpl="t"><span style="color: rgb(255, 106, 0);caret-color: rgb(255, 0, 0);font-size: 15px;">领域驱动的代码分层</span></strong></span></p> </section> </section> </section> <p><br></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">可以使用不同的 Java 项目发布不同的微服务对领域进行隔离,也可以在同一个 Java 项目中,使用不同 module 进行领域隔离。这里我们使用 module 进行领域隔离的实现。但是无论采用何种方式进行领域隔离,领域之间的交互只能使用对方的二方包或者 API 层提供的 HTTP 服务,而不能直接引入其他领域的其他服务。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br style="box-sizing: border-box;">在每个领域内部,相对于 MVC 对应用三层架构的拆分,领域驱动的设计将应用模块内部分为如图示的四层。<br style="box-sizing: border-box;"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <p><img class="rich_pages wxw-img" data-backh="656" data-backw="579" data-ratio="1.135064935064935" src="/upload/514b74e19628d31348233342bace600e.jpg" data-type="jpeg" data-w="770" style="box-sizing: border-box;display: block;margin: 20px auto;cursor: zoom-in;height: auto;width: 100%;"></p> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">用户接口层</span></strong> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br style="box-sizing: border-box;">负责直接面向外部用户或者系统,接收外部输入,并返回结果,例如二方包的实现类、Spring MVC 中的 Controller、特定的数据视图转换器等通常位于该层。在代码层面常常使用的包命名可以是 interface, api, facade 等。用户接口层的入参、出参类定义采用 POJO 风格。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br style="box-sizing: border-box;">用户接口层是轻的一层,不含业务逻辑。安全认证,简单的入参校验(例如使用 @Valid 注解),访问日志记录,统一的异常处理逻辑,统一返回值封装应当在这层完成。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br style="box-sizing: border-box;">用户接口层所需要的功能实现是由应用层完成,这里一般不需要进行依赖倒置。编码时,该层可以直接引入应用层中定义的接口,因而该层依赖应用层。需要注意的是,虽然理论上用户接口层可以直接使用领域层和基础设施层的能力,但这里建议大家在对这种用法熟练掌握前,最好采用严格的分层架构,即当前层只依赖其下方相邻的一层。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">应用层</span></strong> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br style="box-sizing: border-box;">应用层具体实现接口层中需要功能,但该层并不实现真正的业务规则,而是根据实际的 use case 来协调调用领域层提供的能力。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br style="box-sizing: border-box;">消息发送、事件监听、事务控制等建议在这一层实现。在代码层面常常使用的包命名可以是 application, service, manager 等。它用来取代 Spring MVC 中 service 层,并把业务逻辑转移到领域层。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">领域层</span></strong> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br style="box-sizing: border-box;">领域层面向对象的,它主要用来体现和实现领域里的对象所具备的固有能力。因此,在领域驱动编程中,领域层的编程实现是不允许依赖其他外部对象的,领域层的编程是在我们对领域内的对象所具备的固有能力和它要在当前业务场景下展现什么样的能力有一定了解后,可以直接编码实现的。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br style="box-sizing: border-box;">例如我们最开始接触面向对象的编程的时候,常常会遇到的一个例子是鸟会飞、狗会游泳,假设我们的业务域只关心这些对象的运动,我们可以做如下的实现。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <pre> <section> <br> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="java"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__class"><span class="code-snippet__keyword">interface</span> <span class="code-snippet__title">Moveable</span> </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">void</span> <span class="code-snippet__title">move</span><span class="code-snippet__params">()</span></span>;</span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">abstract</span> <span class="code-snippet__class"><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">Animal</span> <span class="code-snippet__keyword">implements</span> <span class="code-snippet__title">Moveable</span> </span>{}</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__class"><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">Bird</span> <span class="code-snippet__keyword">extends</span> <span class="code-snippet__title">Animal</span> </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">void</span> <span class="code-snippet__title">move</span><span class="code-snippet__params">()</span></span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">//try to fly</span></span></code><code><span class="code-snippet_outer"> System.out.println(<span class="code-snippet__string">"I'am flying"</span>);</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__class"><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">Dog</span> <span class="code-snippet__keyword">extends</span> <span class="code-snippet__title">Animal</span> </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">void</span> <span class="code-snippet__title">move</span><span class="code-snippet__params">()</span></span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">//try to swim</span></span></code><code><span class="code-snippet_outer"> System.out.println(<span class="code-snippet__string">"I'am swimming"</span>);</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <section> <br> </section></pre> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">基于领域驱动的编程需要这样(充血模型)去实现对象的能力,而不是像我们在 MVC 架构中常常使用贫血模型,把业务逻辑写在 service 中。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br style="box-sizing: border-box;">当然,即使采用了这样的编程方式,距离实现领域驱动还差的远,一些看似简单的问题就可能给我们带来巨大的不安感。例如复杂的对象应当如何初始化和持久化?同样一个事物在不同领域都存在,但其关注点不同时这个事物应当分别怎么抽象?不同领域的对象需要对方的信息时,应当怎么获取?</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br style="box-sizing: border-box;">这些问题,我们也会在代码示例部分尝试给出一些参考的方案。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">基础设施层</span></strong> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br style="box-sizing: border-box;">基础设施层为上面各层提供通用的技术能力,例如监听、发送消息的能力,数据库/缓存/NoSQL数据库/文件系统等仓储的 CRUD 能力等。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br mpa-from-tpl="t"></span> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <section data-mpa-template="t" mpa-from-tpl="t"> <section data-role="title" data-tools="135编辑器" data-id="107115" mpa-from-tpl="t"> <section style="text-align: left;margin: 10px auto;" mpa-from-tpl="t"> <section style="display: inline-block;" mpa-from-tpl="t"> <section style="border-width: 1px;border-style: solid;border-color: rgb(255, 106, 0);padding: 4px;" mpa-from-tpl="t"> <section style="width: 30px;height: 30px;background-color: rgb(255, 106, 0);" mpa-from-tpl="t"> <section style="font-size: 16px;letter-spacing: 1.5px;color: #ff6a00fff;line-height: 30px;" hm_fix="320:270" mpa-from-tpl="t"> <span style="color:#ff
作者:微信小助手
<p style="margin-bottom: 10px;margin-top: 10px;"><span style="color: rgb(0, 122, 170);"><strong><span style="color: rgb(0, 122, 170);font-size: 15px;">目录</span></strong></span></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;letter-spacing: 2px;">背景介绍<br></span></p></li> <li><p><span style="font-size: 15px;letter-spacing: 2px;">什么是分布式事务<br></span></p></li> <li><p><span style="font-size: 15px;letter-spacing: 2px;">什么叫做逆向补偿呢<br></span></p></li> <li><p><span style="font-size: 15px;letter-spacing: 2px;">互联网最流行的分布式事务组件seata</span></p></li> <li><p><span style="font-size: 15px;letter-spacing: 2px;">总结</span><span style="font-size: 15px;letter-spacing: 1px;"><br></span></p></li> </ul> <section> <br> </section> <article tabindex="0"> <section style="box-sizing: border-box;font-size: 16px;"> <section style="text-align: center;justify-content: center;margin: 10px 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: auto;vertical-align: top;min-width: 10%;max-width: 100%;height: auto;border-bottom: 1px solid rgb(126, 169, 195);border-bottom-right-radius: 0px;line-height: 0;box-sizing: border-box;"> <section style="margin-right: 0%;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="letter-spacing: 0px;line-height: 1.8;font-size: 15px;color: rgb(126, 169, 195);padding-right: 5px;padding-left: 5px;box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong style="box-sizing: border-box;">背景</strong></p> </section> </section> <section style="margin-right: 0%;margin-bottom: -3px;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 5px;height: 5px;vertical-align: top;overflow: hidden;border-width: 0px;border-radius: 202px;border-style: none;border-color: rgb(62, 62, 62);background-color: rgb(126, 169, 195);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> <p><br></p> <p><span style="font-size: 15px;">大家好,今天给大家分享一个在 2022 年出去面试 Java 几乎必问的一个技术,那就是 seata。</span></p> <p><br></p> <p><span style="font-size: 15px;">什么??你才看了第一句话心里有闪现了无数个问号?因为没听说过 seata 这个东西?</span></p> <p><br></p> <p><span style="font-size: 15px;">没关系,为了避免兄弟们出去面试被问到 seata 的时候,一脸蒙圈,我们今天就把这个东西给大家讲明白。</span></p> <p><br></p> <p><span style="font-size: 15px;">既然要给大家讲什么是 seata,那就得先说一下这个东西的定位,这东西就是现在很火的 Spring Cloud Alibaba 里的一个组件,是专门帮助我们解决分布式事务问题的,也就是说,seata 是一个分布式事务框架。</span></p> <p><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="text-align: center;justify-content: center;margin: 10px 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: auto;vertical-align: top;min-width: 10%;max-width: 100%;height: auto;border-bottom: 1px solid rgb(126, 169, 195);border-bottom-right-radius: 0px;line-height: 0;box-sizing: border-box;"> <section style="margin-right: 0%;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="letter-spacing: 0px;line-height: 1.8;font-size: 15px;color: rgb(126, 169, 195);padding-right: 5px;padding-left: 5px;box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong style="box-sizing: border-box;">什么是分布式事务</strong></p> </section> </section> <section style="margin-right: 0%;margin-bottom: -3px;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 5px;height: 5px;vertical-align: top;overflow: hidden;border-width: 0px;border-radius: 202px;border-style: none;border-color: rgb(62, 62, 62);background-color: rgb(126, 169, 195);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> <p><br></p> <p><span style="font-size: 15px;">那可能很多小伙伴很蒙圈了,什么是分布式事务?好吧,为了保证大家能继续看下去,我们先说一下什么是分布式事务这个问题。</span></p> <p><br></p> <p><span style="font-size: 15px;">举个最简单的例子,假设现在你负责了一个订单系统,一个库存系统,一个营销系统,然后呢,当你的订单系统收到用户一个请求要创建订单的时候,这个时候你得做三件事情。</span></p> <p><br></p> <p><span style="font-size: 15px;">第一,调用库存系统的接口锁定库存,第二,调用调用营销系统的接口锁定优惠券,第三,你订单系统自己得在 MySQL 里插入一系列订单的数据。</span></p> <p><br></p> <section style="margin-bottom: 10px;"> <span style="font-size: 15px;color: rgb(0, 122, 170);">比如下图 1 所示:</span> </section> <section style="text-align: center;margin-bottom: 10px;"> <img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.4917825537294564" data-s="300,640" src="/upload/4426712503359af07c0c078ae71e442d.png" data-type="png" data-w="791" style=""> </section> <p style="text-align: center;"><span style="font-size: 12px;"><em>图 1</em></span></p> <p><br></p> <p><span style="font-size: 15px;">那么现在问题来了,你订单系统有自己的订单数据库,可以去插入订单数据,那库存系统是不是也应该有自己的库存数据库,去锁定库存数据?</span></p> <p><br></p> <p><span style="font-size: 15px;">营销系统是不是应该有自己的营销数据库,去锁定优惠券?当然是了!每个人都有自己的数据库,这一个都不能少。</span></p> <p><br></p> <section style="margin-bottom: 10px;"> <span style="font-size: 15px;color: rgb(0, 122, 170);">如下图 2 所示:</span> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.44975124378109455" data-s="300,640" src="/upload/88512f3942700087015bc9ab506345a1.png" data-type="png" data-w="1005" style=""></p> <p style="text-align: center;"><span style="font-size: 12px;"><em>图 2</em></span><br></p> <p><br></p> <p><span style="font-size: 15px;">那现在问题又来了,既然一次创建订单的请求,要涉及到订单、库存、营销三个系统,分别操作各自自己的三个数据库,才能完成这次请求。</span></p> <p><br></p> <p><span style="font-size: 15px;">那是不是可能会出现这么一种情况,首先呢,你先调用库存系统,锁定了库存了,O 了。</span></p> <p><br></p> <p><span style="font-size: 15px;">接着呢,你又调用了营销系统,锁定了优惠券,也 O 了。最后呢,当你订单系统要往自己的订单数据库里插入数据的时候,网络抽风了,导致你这一次插入订单数据失败了,直接 exception 异常了,你蒙圈了。</span></p> <p><br></p> <section style="margin-bottom: 10px;"> <span style="font-size: 15px;color: rgb(0, 122, 170);">如下图 3 所示:</span> </section> <section style="text-align: center;margin-bottom: 10px;"> <img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.4147557328015952" data-s="300,640" src="/upload/d6fff23e269dd6337703689a7ab2740c.png" data-type="png" data-w="1003" style=""> </section> <p style="text-align: center;"><span style="font-size: 12px;"><em>图 3</em></span><br></p> <p><br></p> <p><span style="font-size: 15px;">那这个时候你觉得可能会产生什么样的问题呢,其实很简单,这个时候你这个订单要购买的商品库存已经被锁定了,你为了下这个订单用的优惠券,也已经被锁定了。</span></p> <p><br></p> <p><span style="font-size: 15px;">结果呢,你的订单自己本身的数据并没进入数据库,然后还返回一个了异常信息给用户说,本次下单失败。</span></p> <p><br></p> <p><span style="font-size: 15px;">但是你说下单失败就失败吧,结果呢,运营看库存数据的时候可能会一脸蒙圈,为啥有一些商品库存被锁定了,结果没有对应的跟订单,而且一直没人付款来购买呢??</span></p> <p><br></p> <p><span style="font-size: 15px;">然后用户自己也有点发蒙,因为一查自己的优惠券,好不容易攒了几张券来买东西,结果现在订单没下成,优惠券状态都搞成已使用了,自己还没法用这些优惠券了。</span></p> <p><br></p> <section style="margin-bottom: 10px;"> <span style="font-size: 15px;color: rgb(0, 122, 170);">如下图 4 所示:</span> </section> <section style="text-align: center;margin-bottom: 10px;"> <img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.609450337512054" data-s="300,640" src="/upload/202da799133f0277e5a31771940e0bd7.png" data-type="png" data-w="1037" style=""> </section> <p style="text-align: center;"><span style="font-size: 12px;"><em>图 4</em></span><br></p> <p><br></p> <p><span style="font-size: 15px;">其实这就是一个非常经典的分布式事务的问题了,你一个创建订单的请求,横跨了订单、库存、营销三个系统,分别涉及三个数据库。</span></p> <p><br></p> <p><span style="font-size: 15px;">所有很可能会发现,你的库存和营销的数据操作都成功了,而且库存和营销数据库里的本地事务都提交了,结果订单插入数据库失败了,订单数据库里的本地事务回滚了,但是库存和营销数据库里的本地事务已经提交了,他们是不会回滚的。</span></p> <p><br></p> <section style="margin-bottom: 10px;"> <span style="font-size: 15px;color: rgb(0, 122, 170);">如下图 5 所示:</span> </section> <p style="text-align: center;margin-bottom: 10px;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.6721479958890031" data-s="300,640" src="/upload/4209e3bd08ef7af1381acbd07b8959aa.png" data-type="png" data-w="973" style=""></p> <p style="text-align: center;"><span style="font-size: 12px;"><em>图 5</em></span><br></p> <p><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="text-align: center;justify-content: center;margin: 10px 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: auto;vertical-align: top;min-width: 10%;max-width: 100%;height: auto;border-bottom: 1px solid rgb(126, 169, 195);border-bottom-right-radius: 0px;line-height: 0;box-sizing: border-box;"> <section style="margin-right: 0%;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="letter-spacing: 0px;line-height: 1.8;font-size: 15px;color: rgb(126, 169, 195);padding-right: 5px;padding-left: 5px;box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong style="box-sizing: border-box;">什么叫做逆向补偿</strong></p> </section> </section> <section style="margin-right: 0%;margin-bottom: -3px;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 5px;height: 5px;vertical-align: top;overflow: hidden;border-width: 0px;border-radius: 202px;border-style: none;border-color: rgb(62, 62, 62);background-color: rgb(126, 169, 195);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> <p><br></p> <p><span style="font-size: 15px;">那既然问题已经找到了,我们希望的应该是什么效果呢?</span></p> <p><br></p> <p><span style="font-size: 15px;">我们其实希望的效果是,如果订单要是插入数据库失败了,订单数据库本地事务回滚了,我们应该想办法去通知一下库存系统和营销系统,把之前在库存数据库和营销数据库里已经提交的数据修改做一个逆向补偿,进行恢复。</span></p> <p><br></p> <p><span style="font-size: 15px;">什么叫做逆向补偿呢?意思就是说,之前库存系统如果在数据库里执行的是 insert,那么此时就应该执行 delete,把之前插入的数据删除了。</span></p> <p><br></p> <p><span style="font-size: 15px;">如果之前执行的 delete,现在就应该执行 insert,把删除的额数据重新插入回去,如果之前执行的是 udpate 语句,现在就应该再次执行一个 update 语句,把数据恢复到更新之前的状态。</span></p> <p><br></p> <section style="margin-bottom: 10px;"> <span style="font-size: 15px;color: rgb(0, 122, 170);">如下图 6 所示:</span> </section> <section style="text-align: center;margin-bottom: 10px;"> <img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5189243027888446" data-s="300,640" src="/upload/2908c6c568ba8547d765bf4904f680e6.png" data-type="png" data-w="1004" style=""> </section> <p style="text-align: center;"><span style="font-size: 12px;"><em>图 6</em></span><br></p> <p><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="text-align: center;justify-content: center;margin: 10px 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: auto;vertical-align: top;min-width: 10%;max-width: 100%;height: auto;border-bottom: 1px solid rgb(126, 169, 195);border-bottom-right-radius: 0px;line-height: 0;box-sizing: border-box;"> <section style="margin-right: 0%;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="letter-spacing: 0px;line-height: 1.8;font-size: 15px;color: rgb(126, 169, 195);padding-right: 5px;padding-left: 5px;box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong style="box-sizing: border-box;">互联网最流行的分布式事务组件 seata</strong></p> </section> </section> <section style="margin-right: 0%;margin-bottom: -3px;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 5px;height: 5px;vertical-align: top;overflow: hidden;border-width: 0px;border-radius: 202px;border-style: none;border-color: rgb(62, 62, 62);background-color: rgb(126, 169, 195);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> <p><br></p> <p><span style="font-size: 15px;">那既然我们想要实现这个效果,这个时候问题就来了,单单依赖我们自己那肯定搞不定这个问题了,这个时候就必须引入 Spring Cloud Alibaba 里的大佬组件,seata。</span></p> <p><br></p> <p><span style="font-size: 15px;">seata 就是专门帮助我们解决这个问题的,如果我们要是在系统里引入 seata 框架之后,其实每个系统里都会嵌入 seata,同时我们还需要去部署一个 seata server。</span></p> <p><br></p> <section style="margin-bottom: 10px;"> <span style="font-size: 15px;color: rgb(0, 122, 170);">如下图 7 所示:</span> </section> <section style="text-align: center;margin-bottom: 10px;"> <img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.4613899613899614" data-s="300,640" src="/upload/8058a364cc2e7d4085cd1330670ece14.png" data-type="png" data-w="1036" style=""> </section> <p style="text-align: center;"><span style="font-size: 12px;"><em>图 7</em></span><br></p> <p><br></p> <p><span style="font-size: 15px;">这个时候,我们的系统运行原理会变成这样:订单系统中的 seata 会发送请求给 seata server 去开启一个全局事务,然后库存系统先运行,他在进行数据库 crud 的时候,这些操作都会被 seata 框架进行拦截。</span></p> <p><br></p> <p><span style="font-size: 15px;">然后 seata 框架会在一个本地事务里,把你的 sql 语句和逆向补偿日志,一起插入到你的库存数据库里去,在库存数据库里必须有一个 undo_log 表,存储 seata 的逆向补偿日志。</span></p> <p><br></p> <p><span style="font-size: 15px;">那这个逆向补偿日志是什么呢?简单,如果你的 sql 是 insert,那逆向补偿日志可以帮助你后续构建 delete 语句来删除,如果你的 sql 是 update,那逆向补偿日志可以记录你更新之前的旧数据,他可以帮助你后续把数据 update 到老版本的状态。</span></p> <p><br></p> <section style="margin-bottom: 10px;"> <span style="font-size: 15px;color: rgb(0, 122, 170);">如下图 8 所示:</span> </section> <section style="text-align: center;margin-bottom: 10px;"> <img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5064805583250249" data-s="300,640" src="/upload/2d80c4e578c0d3955df8afe079b381f4.png" data-type="png" data-w="1003" style=""> </section> <p style="text-align: center;"><span style="font-size: 12px;"><em>图 8</em></span><br></p> <p><br></p> <p><span style="font-size: 15px;">你库存系统的 sql 语句和他们的补偿日志,是在一个本地事务里一起提交的,一起成功或者一起失败,所以但凡你的库存系统更新成功了,就一定会有对应的补偿日志也会在库存 数据库里的,以备不时之需,营销系统其实也是相同的运行原理。</span></p> <p><br></p> <p><span style="font-size: 15px;">那么假设说库存系统和营销系统,按照这个思路都执行完毕了,到订单系统了,他结果撂挑子了,插入订单数据库失败。</span></p> <p><br></p> <p><span style="font-size: 15px;">当然,在插入的时候其实也会有对应的补偿日志会一起提交,但是因为这个时候网络问题,导致插入订单和插入补偿日志一起失败了。</span></p> <p><br></p> <p><span style="font-size: 15px;">所以此时订单系统的 seata 就会上报 seata server 说,大哥,我这儿完犊子了,您要不通知库存和营销两个兄弟,逆向补偿一下吧。</span></p> <p><span style="font-size: 15px;"><br></span></p> <section style="margin-bottom: 10px;"> <span style="font-size: 15px;color: rgb(0, 122, 170);">如下图 9 所示:</span> </section> <section style="text-align: center;margin-bottom: 10px;"> <img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5171736997055937" data-s="300,640" src="/upload/2ba1d9fce24a5344ae62de25378c7ed5.png" data-type="png" data-w="1019" style=""> </section> <p style="text-align: center;"><span style="font-size: 12px;"><em>图 9</em></span><br></p> <p><br></p> <p><span style="font-size: 15px;">接着 seata server 发现说,这分布式事务都失败了,那赶紧的,他会通知库存系统和营销系统里的 seata 框架小兄弟说,兄弟们,赶紧的,把之前插入你们数据库里的 undo_log 表里的补偿日志拿出来,构建一下逆向补偿 sql。</span></p> <p><br></p> <p><span style="font-size: 15px;">之前是 insert 你就给我弄个 delete,之前是 delete 你就给我弄个 insert,之前是 update 你还是 update,逆向补偿 sql 赶紧跑一把,把数据给我恢复了,前队改后队,跑步前进,hurry up 起来。</span></p> <p><br></p> <section style="margin-bottom: 10px;"> <span style="font-size: 15px;color: rgb(0, 122, 170);">如下图 10 所示:</span> </section> <section style="text-align: center;margin-bottom: 10px;"> <img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5510009532888466" data-s="300,640" src="/upload/c10e9090c415dbf67fc13175bcbd073b.png" data-type="png" data-w="1049" style=""> </section> <p style="text-align: center;"><span style="font-size: 12px;"><em>图 10</em></span><br></p> <p><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="text-align: center;justify-content: center;margin: 10px 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: auto;vertical-align: top;min-width: 10%;max-width: 100%;height: auto;border-bottom: 1px solid rgb(126, 169, 195);border-bottom-right-radius: 0px;line-height: 0;box-sizing: border-box;"> <section style="margin-right: 0%;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="letter-spacing: 0px;line-height: 1.8;font-size: 15px;color: rgb(126, 169, 195);padding-right: 5px;padding-left: 5px;box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong style="box-sizing: border-box;">总结</strong></p> </section> </section> <section style="margin-right: 0%;margin-bottom: -3px;margin-left: 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 5px;height: 5px;vertical-align: top;overflow: hidden;border-width: 0px;border-radius: 202px;border-style: none;border-color: rgb(62, 62, 62);background-color: rgb(126, 169, 195);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> <p><br></p> <p><span style="font-size: 15px;">太棒了,到这个时候为止,我们就发现 seata 老大的作用了,你订单、库存、营销三个系统随便跑,有谁失败了,seata server 收到你的失败通知,就会告诉别的系统用 undo log 日志构建补偿 sql,把数据都给回滚了,完美。</span></p> </article>
作者:微信小助手
<blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="79" data-source-title="" data-mpa-powered-by="yiban.io"> <section class="js_blockquote_digest"> <section> <p style="text-align: left;"><span style="color: rgb(0, 82, 255);"><strong><span style="font-size: 14px;">来自:CSDN,作者:如漩涡<br></span></strong></span></p> <p style="text-align: left;"><span style="color: rgb(0, 82, 255);"><strong><span style="font-size: 14px;">链接:https://blog.csdn.net/m0_37701381/article/details/104163877</span></strong></span></p> </section> </section> </blockquote> <h3 style="margin-top: 1.5em;margin-right: 5px;margin-bottom: 2em;padding: 8px 15px;font-weight: bold;font-size: 1.3em;color: rgb(255, 255, 255);line-height: inherit;letter-spacing: 2px;background-image: linear-gradient(to right bottom, rgb(0, 188, 212), rgb(63, 81, 181));background-color: rgb(63, 81, 181);border-left: 10px solid rgb(51, 51, 51);border-radius: 5px;text-shadow: rgb(102, 102, 102) 1px 1px 1px;box-shadow: rgb(102, 102, 102) 1px 1px 2px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;white-space: normal;"><span style="font-size: inherit;color: inherit;line-height: inherit;">前言</span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">近期做了一个前后端合并的spring boot项目,但是要求达成exe文件,提供给不懂电脑的小白安装使用,就去研究了半天,踩了很多坑,写这篇文章,是想看到这篇文章的人,按照我的步骤走,能少踩坑。</span></p> <h3 style="margin-top: 1.5em;margin-right: 5px;margin-bottom: 2em;padding: 8px 15px;font-weight: bold;font-size: 1.3em;color: rgb(255, 255, 255);line-height: inherit;letter-spacing: 2px;background-image: linear-gradient(to right bottom, rgb(0, 188, 212), rgb(63, 81, 181));background-color: rgb(63, 81, 181);border-left: 10px solid rgb(51, 51, 51);border-radius: 5px;text-shadow: rgb(102, 102, 102) 1px 1px 1px;box-shadow: rgb(102, 102, 102) 1px 1px 2px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;white-space: normal;"><span style="font-size: inherit;color: inherit;line-height: inherit;">准备</span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">准备工作:</span></p> <ul class="list-paddingleft-1" style="width: 557.438px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;list-style-type: circle;"> <li style="font-size: 15px;"><p style="line-height: 2em;"><span style="font-size: 15px;">一个jar包,没有bug能正常启动的jar包</span></p></li> <li style="font-size: 15px;"><p style="line-height: 2em;"><span style="font-size: 15px;">exe4j,一个将jar转换成exe的工具</span></p></li> <li style="font-size: 15px;"><p style="line-height: 2em;"><span style="font-size: 15px;">inno setup,一个将依赖和exe一起打成一个安装程序的工具</span></p></li> </ul> <p style="color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;"><span style="font-size: 15px;"><span style="letter-spacing: 0px;"></span></span></p> <h3 style="margin-top: 1.5em;margin-right: 5px;margin-bottom: 2em;padding: 8px 15px;font-weight: bold;font-size: 1.3em;color: rgb(255, 255, 255);line-height: inherit;letter-spacing: 2px;background-image: linear-gradient(to right bottom, rgb(0, 188, 212), rgb(63, 81, 181));background-color: rgb(63, 81, 181);border-left: 10px solid rgb(51, 51, 51);border-radius: 5px;text-shadow: rgb(102, 102, 102) 1px 1px 1px;box-shadow: rgb(102, 102, 102) 1px 1px 2px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;white-space: normal;"><span style="font-size: inherit;color: inherit;line-height: inherit;">开始</span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">以我为例子,我将jar包放在了桌面</span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-ratio="0.9236641221374046" data-type="png" data-w="131" src="/upload/be04080c8f775c2ccbfc3a41684b813c.png"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">打开安装好的exe4j</span><br></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065743" data-ratio="0.7644787644787645" src="/upload/585562f95112e0e1a4efffce8df35ccf.jpg" data-type="jpeg" data-w="1036" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">直接下一步进入界面,选择JAVA转EXE</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065746" data-ratio="0.7641963426371511" src="/upload/585562f95112e0e1a4efffce8df35ccf.jpg" data-type="jpeg" data-w="1039" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">然后点下一步,输入名称和输出路径</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065748" data-ratio="0.7690086621751684" src="/upload/832cbf50ef3699dd46d5790c92702c07.jpg" data-type="jpeg" data-w="1039" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">继续点击下一步,选择启动模式</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065747" data-ratio="0.770048309178744" src="/upload/6daadd271255a7d775ad4db17e4e11cd.jpg" data-type="jpeg" data-w="1035" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">下方有个选项,需要设置打包后的程序兼容32和64位系统</span></p> <p><img class="rich_pages wxw-img" data-ratio="0.7736030828516378" src="/upload/c393c13ac6e16e9b5d79c64b31b1b7fe.png" data-type="png" data-w="1038"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">进来后勾选上</span><br></p> <p><img class="rich_pages wxw-img" data-ratio="0.763915547024952" src="/upload/7d4f0cef26f7174a02dbc3c186b29fd0.png" data-type="png" data-w="1042"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">然后一直下一步,一直出现如下界面,开始选择jar包以及配置</span><br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">在VM参数配置的地方加上:-Dfile.encoding=utf-8</span></p> <p><img class="rich_pages wxw-img" data-ratio="0.7660594439117929" src="/upload/1e9cbcb7c3ddf0b5fa774e05d2c9d79b.png" data-type="png" data-w="1043"></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065752" data-ratio="0.7615384615384615" src="/upload/37990ebfe008b171154a452d62df277.jpg" data-type="jpeg" data-w="1040" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065754" data-ratio="0.7632575757575758" src="/upload/c87914d487c8d09884465ec3ffdfee77.jpg" data-type="jpeg" data-w="1056" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065755" data-ratio="0.7689357622243528" src="/upload/f2f77328bf43078f9d5b180f2288b549.jpg" data-type="jpeg" data-w="1043" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">点击下一步,配置JRE</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065753" data-ratio="0.7605363984674329" src="/upload/5fa42ccd380d99bfa7b37a3a0c9c27f6.jpg" data-type="jpeg" data-w="1044" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">下拉框点击后进入如下界面</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065756" data-ratio="0.7612655800575263" src="/upload/37990ebfe008b171154a452d62df277.jpg" data-type="jpeg" data-w="1043" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065758" data-ratio="0.5459016393442623" src="/upload/9345b7a643c4da440f01bec7dff10eb3.jpg" data-type="jpeg" data-w="610" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">照着这个样子写的目的是,最终会把本地jre目录和exe一起打包,让exe文件自己去根据路径去查找一起打包的jre,可不用再安装jdk</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065757" data-ratio="0.7651006711409396" src="/upload/5fd6af1f666c96b61ba64eb99e54c52b.jpg" data-type="jpeg" data-w="1043" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">接着下一步,选择Client VM,<span style="letter-spacing: 0px;">分享:</span></span><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&mid=2247489332&idx=2&sn=65de5886e13b98116c8432d7d10ae4bc&chksm=eb539202dc241b14010f70edf89dc37c7629b5e2b7add50fd3f58070ecf2c14260196bf147d8&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" style="text-decoration: underline;letter-spacing: 0px;color: rgb(136, 136, 136);font-size: 15px;"><span style="letter-spacing: 0px;color: rgb(136, 136, 136);font-size: 15px;">46 张 PPT 弄懂 JVM 性能调优!</span></a></p> <p><img class="rich_pages wxw-img" data-ratio="0.7672413793103449" src="/upload/cd55defa281541d39afbe7cbbd5d86a3.png" data-type="png" data-w="1044"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">然后一直下一步,最终出现如下界面</span><br></p> <p><img class="rich_pages wxw-img" data-ratio="0.7675312199807877" src="/upload/f545c0137779412564e03ffb2728796b.png" data-type="png" data-w="1041"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">这个时候你会发现桌面多了一个demo.exe文件,这个时候先别着急点开,接下来就是将jre和exe文件再打个包合并,达到在没有jdk电脑环境下也能运行。</span></p> <section style="color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;"> <br> </section> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">打开inno setup,左上角File - New</span></p> <p><img class="rich_pages wxw-img" data-ratio="0.7731629392971247" src="/upload/c9be30fac6d6b19488200889d91c938e.png" data-type="png" data-w="626"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">直接点下一步,填写配置,应用名称,版本等,随意</span><br></p> <p><img class="rich_pages wxw-img" data-ratio="0.7731629392971247" src="/upload/23ba6242c1f8bcfe2e1d59069bae48e1.png" data-type="png" data-w="626"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">然后点击下一步,这个地方默认就行,直接下一步</span><br></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065764" data-ratio="0.7731629392971247" src="/upload/13410c4adf35d17aef3f0d4db1bb7d44.png" data-type="png" data-w="626" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">接着选择生成好的exe文件</span></p> <p><img class="rich_pages wxw-img" data-ratio="0.7731629392971247" src="/upload/5392b2a4beb95171419ebeb30935ca7e.png" data-type="png" data-w="626"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">然后下一步,进入这个界面保持默认,直接下一步</span><br></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065767" data-ratio="0.7731629392971247" src="/upload/878529f373bf96bd5cb4ee8374c664e1.jpg" data-type="jpeg" data-w="626" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">依旧下一步,不用管</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065768" data-ratio="0.7731629392971247" src="/upload/f056b2a5ce93c0106239cdd9edf1d39b.jpg" data-type="jpeg" data-w="626" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">继续下一步,这里是选择语言</span></p> <p><img class="rich_pages wxw-img" data-ratio="0.7731629392971247" src="/upload/16aa0be09198a0c6dd2be9115b960e61.png" data-type="png" data-w="626"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">然后就是选择输出路径和填写安装程序的名字了</span><br></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065770" data-ratio="0.7731629392971247" src="/upload/b5f89340c2df044b7992e76deb7fa3bd.jpg" data-type="jpeg" data-w="626" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">然后下一步,直接点Next,然后结束</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">配置到最后一步了,脚本文件,到这里会弹出问你是否马上编译,选择否,先把脚本写好再自己编译:</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065771" data-ratio="0.6222222222222222" src="/upload/d6cdf9ea41322de6a35beac9c129e2c1.jpg" data-type="jpeg" data-w="1080" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">然后到了最后一步了,把本地的JRE写进脚本</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065772" data-ratio="0.28169014084507044" src="/upload/4dbfee5ff372fc7a2ec50f2c474ddd81.jpg" data-type="jpeg" data-w="639" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065774" data-ratio="0.28169014084507044" src="/upload/7364b29b44c69e81da01fd60689964c0.jpg" data-type="jpeg" data-w="639" style="margin-right: auto;margin-left: auto;display: block;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 14px;"> <span style="font-size: 15px;">图片</span> </figcaption> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065773" data-ratio="0.22685185185185186" src="/upload/7364b29b44c69e81da01fd60689964c0.jpg" data-type="jpeg" data-w="1080" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">Source: "自己本地JRE路径*"; DestDir: "{app}{#MyJreName}"; Flags: ignoreversion recursesubdirs createallsubdirs</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">然后直接编译就好了,会提示保存当前脚本,随便起个名字,下个还可以继续用</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065775" data-ratio="0.2018348623853211" data-type="jpeg" data-w="436" src="/upload/9becf9d13bfdce8e34c0f0de0439e83.jpg" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065776" data-ratio="0.42470389170896783" src="/upload/dc203722c8010b082877aa948ab16a26.jpg" data-type="jpeg" data-w="591" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">然后等待绿色滚动条结束</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065779" data-ratio="0.37858220211161386" src="/upload/a019b9ba6d4599d82ecbc9e92ccf3aef.jpg" data-type="jpeg" data-w="663" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">当绿色滚动条结束后,桌面会多了一个setup.exe文件</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065777" data-ratio="0.8770491803278688" data-type="jpeg" data-w="122" src="/upload/c8c4ad232bce87c361d2674f447d4e88.jpg" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">也同时会跳出一个安装的,因为程序帮你自动启动生成的安装程序了,安装就可以了,安装的时候记得勾选创建快捷方式</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-fileid="100065778" data-ratio="0.42470389170896783" src="/upload/dc203722c8010b082877aa948ab16a26.jpg" data-type="jpeg" data-w="591" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;line-height: 26px;color: rgb(89, 89, 89);"><span style="font-size: 15px;">这个就是最后的程序了,双击运行就可以看到结果了,把setup.exe文件给别人安装,就都可以看到自己的程序了!</span></p> </section>
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;text-align: left;padding: 5px;font-size: 16px;color: rgb(53, 53, 53);word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;" 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);">Arthas</span>是阿里开源的 Java 诊断工具,相比 JDK 内置的诊断工具,要更人性化,并且功能强大,可以实现许多问题的一键定位,而且可以一键反编译类查看源码,甚至是直接进行生产代码热修复,实现在一个工具内快速定位和修复问题的一站式服务。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">今天,我就带你使用 Arthas 定位一个 CPU 使用高的问题,系统学习下这个工具的使用。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">首先,下载并启动 Arthas:</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("https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQRgcQhia7zATsR2JqgxLZHkfKEuMET97Zfr2hkdq8xaV1rI2ZmjiamHVm0X39CXzAr7wgSNLBRiazrj/640?wx_fmt=svg") 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;">curl -O https:<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//alibaba.github.io/arthas/arthas-boot.jar</span><br>java -jar arthas-boot.jar<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">启动后,直接找到我们要排查的 JVM 进程,然后可以看到 Arthas 附加进程成功:</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("https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQRgcQhia7zATsR2JqgxLZHkfKEuMET97Zfr2hkdq8xaV1rI2ZmjiamHVm0X39CXzAr7wgSNLBRiazrj/640?wx_fmt=svg") 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;"><br>[INFO] arthas-boot version: <span style="color: #986801;line-height: 26px;">3.1</span><span style="color: #986801;line-height: 26px;">.7</span><br>[INFO] Found existing java process, please choose one and hit RETURN.<br>* [<span style="color: #986801;line-height: 26px;">1</span>]: <span style="color: #986801;line-height: 26px;">12707</span><br> [<span style="color: #986801;line-height: 26px;">2</span>]: <span style="color: #986801;line-height: 26px;">30724</span> org.jetbrains.jps.cmdline.Launcher<br> [<span style="color: #986801;line-height: 26px;">3</span>]: <span style="color: #986801;line-height: 26px;">30725</span> org.geekbang.time.commonmistakes.troubleshootingtools.highcpu.HighCPUApplication<br> [<span style="color: #986801;line-height: 26px;">4</span>]: <span style="color: #986801;line-height: 26px;">24312</span> sun.tools.jconsole.JConsole<br> [<span style="color: #986801;line-height: 26px;">5</span>]: <span style="color: #986801;line-height: 26px;">26328</span> org.jetbrains.jps.cmdline.Launcher<br> [<span style="color: #986801;line-height: 26px;">6</span>]: <span style="color: #986801;line-height: 26px;">24106</span> org.netbeans.lib.profiler.server.ProfilerServer<br><span style="color: #986801;line-height: 26px;">3</span><br>[INFO] arthas home: /Users/zhuye/.arthas/lib/<span style="color: #986801;line-height: 26px;">3.1</span><span style="color: #986801;line-height: 26px;">.7</span>/arthas<br>[INFO] Try to attach process <span style="color: #986801;line-height: 26px;">30725</span><br>[INFO] Attach process <span style="color: #986801;line-height: 26px;">30725</span> success.<br>[INFO] arthas-client connect <span style="color: #986801;line-height: 26px;">127.0</span><span style="color: #986801;line-height: 26px;">.0</span><span style="color: #986801;line-height: 26px;">.1</span> <span style="color: #986801;line-height: 26px;">3658</span><br> ,---. ,------. ,--------.,--. ,--. ,---. ,---.<br> / O \ | .--. <span style="color: #50a14f;line-height: 26px;">''</span>--. .--<span style="color: #50a14f;line-height: 26px;">'| '</span>--<span style="color: #50a14f;line-height: 26px;">' | / O \ '</span> .-<span style="color: #50a14f;line-height: 26px;">'<br>| .-. || '</span>--<span style="color: #50a14f;line-height: 26px;">'.'</span> | | | .--. || .-. |`. `-.<br>| | | || |\ \ | | | | | || | | |.-<span style="color: #50a14f;line-height: 26px;">' |<br>`--'</span> `--<span style="color: #50a14f;line-height: 26px;">'`--'</span> <span style="color: #50a14f;line-height: 26px;">'--'</span> `--<span style="color: #50a14f;line-height: 26px;">' `--'</span> `--<span style="color: #50a14f;line-height: 26px;">'`--'</span> `--<span style="color: #50a14f;line-height: 26px;">'`-----'</span><br><br>wiki https:<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//alibaba.github.io/arthas</span><br>tutorials https:<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//alibaba.github.io/arthas/arthas-tutorials</span><br>version <span style="color: #986801;line-height: 26px;">3.1</span><span style="color: #986801;line-height: 26px;">.7</span><br>pid <span style="color: #986801;line-height: 26px;">30725</span><br>time <span style="color: #986801;line-height: 26px;">2020</span>-<span style="color: #986801;line-height: 26px;">01</span>-<span style="color: #986801;line-height: 26px;">30</span> <span style="color: #986801;line-height: 26px;">15</span>:<span style="color: #986801;line-height: 26px;">48</span>:<span style="color: #986801;line-height: 26px;">33</span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">输出 help 命令,可以看到所有支持的命令列表。今天,我们会用到 <span style="font-weight: 700;color: rgb(248, 57, 41);">dashboard</span>、<span style="font-weight: 700;color: rgb(248, 57, 41);">thread</span>、<span style="font-weight: 700;color: rgb(248, 57, 41);">jad</span>、<span style="font-weight: 700;color: rgb(248, 57, 41);">watch</span>、<span style="font-weight: 700;color: rgb(248, 57, 41);">ognl</span> 命令,来定位这个 <span style="font-weight: 700;color: rgb(248, 57, 41);">HighCPUApplication</span> 进程。你可以通过官方文档:https://arthas.aliyun.com/doc/commands.html,查看这些命令的完整介绍:</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.6938775510204082" src="/upload/d5b05b2d3122d1b8e94f2f3ca6f54855.png" data-type="png" data-w="2156" 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;">dashboard 命令用于整体展示进程所有线程、内存、GC 等情况,其输出如下:</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.6637806637806638" src="/upload/a73c1c66c440aff5f35dfc4efa8c80.png" data-type="png" data-w="2772" 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;">可以看到,CPU 高并不是 GC 引起的,占用 CPU 较多的线程有 8 个,其中 7 个是 ForkJoinPool.commonPool。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">ForkJoinPool.commonPool 是并行流默认使用的线程池。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">所以,此次 CPU 高的问题,应该出现在某段并行流的代码上。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">接下来,要查看最繁忙的线程在执行的线程栈,可以使用 thread -n 命令。这里,我们查看下最忙的 8 个线程:</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("https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQRgcQhia7zATsR2JqgxLZHkfKEuMET97Zfr2hkdq8xaV1rI2ZmjiamHVm0X39CXzAr7wgSNLBRiazrj/640?wx_fmt=svg") 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;">thread -n <span style="color: #986801;line-height: 26px;">8</span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">输出如下:</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.6464237516869096" src="/upload/dad924d24f58014013a7fb7b202dfbe7.png" data-type="png" data-w="2964" 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;">可以看到,由于这些线程都在处理 MD5 的操作,所以占用了大量 CPU 资源。我们希望分析出代码中哪些逻辑可能会执行这个操作,所以需要从方法栈上找出我们自己写的类,并重点关注。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">由于主线程也参与了 ForkJoinPool 的任务处理,因此我们可以通过主线程的栈看到需要重点关注 org.geekbang.time.commonmistakes.troubleshootingtools.highcpu.HighCPUApplication 类的 doTask 方法。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">接下来,使用 jad 命令直接对 HighCPUApplication 类反编译:</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("https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQRgcQhia7zATsR2JqgxLZHkfKEuMET97Zfr2hkdq8xaV1rI2ZmjiamHVm0X39CXzAr7wgSNLBRiazrj/640?wx_fmt=svg") 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;">jad org.geekbang.time.commonmistakes.troubleshootingtools.highcpu.HighCPUApplication<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">可以看到,调用路径是 main->task()->doTask(),当 doTask 方法接收到的 int 参数等于某个常量的时候,会进行 1 万次的 MD5 操作,这就是耗费 CPU 的来源。那么,这个魔法值到底是多少呢?</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.6464237516869096" src="/upload/4b6869854462243a05edcf91e1a3ae89.png" data-type="png" data-w="2964" 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;">你可能想到了,通过 jad 命令继续查看 User 类即可。这里因为是 Demo,所以我没有给出很复杂的逻辑。在业务逻辑很复杂的代码中,判断逻辑不可能这么直白,我们可能还需要分析出 doTask 的“慢”会慢在什么入参上。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这时,我们可以使用 watch 命令来观察方法入参。如下命令,表示需要监控耗时超过 100 毫秒的 doTask 方法的入参,并且输出入参,展开 2 层入参参数:</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("https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQRgcQhia7zATsR2JqgxLZHkfKEuMET97Zfr2hkdq8xaV1rI2ZmjiamHVm0X39CXzAr7wgSNLBRiazrj/640?wx_fmt=svg") 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;">watch org.geekbang.time.commonmistakes.troubleshootingtools.highcpu.HighCPUApplication doTask <span style="color: #50a14f;line-height: 26px;">'{params}'</span> <span style="color: #50a14f;line-height: 26px;">'#cost>100'</span> -x <span style="color: #986801;line-height: 26px;">2</span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">可以看到,所有耗时较久的 doTask 方法的入参都是 0,意味着 User.ADMN_ID 常量应该是 0。</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.47126436781609193" src="/upload/6a14ecdf9357ea887a3cfe5150948a69.png" data-type="png" data-w="2262" 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;">最后,我们使用 ognl 命令来运行一个表达式,直接查询 User 类的 ADMIN_ID 静态字段来验证是不是这样,得到的结果果然是 0:</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("https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQRgcQhia7zATsR2JqgxLZHkfKEuMET97Zfr2hkdq8xaV1rI2ZmjiamHVm0X39CXzAr7wgSNLBRiazrj/640?wx_fmt=svg") 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;">[arthas@<span style="color: #986801;line-height: 26px;">31126</span>]$ ognl <span style="color: #50a14f;line-height: 26px;">'@org.geekbang.time.commonmistakes.troubleshootingtools.highcpu.User@ADMIN_ID'</span><br><span style="color: #4078f2;line-height: 26px;">@Integer</span>[<span style="color: #986801;line-height: 26px;">0</span>]<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">需要额外说明的是,由于 monitor、trace、watch 等命令是通过字节码增强技术来实现的,会在指定类的方法中插入一些切面来实现数据统计和观测,因此诊断结束要执行 shutdown 来还原类或方法字节码,然后退出 Arthas。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">在这个案例中,我们通过 Arthas 工具排查了高 CPU 的问题:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 首先,通过 dashboard + thread 命令,基本可以在几秒钟内一键定位问题,找出消耗 CPU 最多的线程和方法栈; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 然后,直接 jad 反编译相关代码,来确认根因; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 此外,如果调用入参不明确的话,可以使用 watch 观察方法入参,并根据方法执行时间来过滤慢请求的入参。 </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;">可见,使用 Arthas 来定位生产问题根本用不着原始代码,也用不着通过增加日志来帮助我们分析入参,一个工具即可完成定位问题、分析问题的全套流程。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">对于应用故障分析,除了阿里 之外,还可以关注去哪儿的 :https://github.com/qunarcorp/bistoury工具,其提供了可视化界面,并且可以针对多台机器进行管理,甚至提供了在线断点调试等功能,模拟 IDE 的调试体验。</p> </section>
作者:微信小助手
<section data-mpa-powered-by="yiban.io"> <br> </section> <section style="margin-top: 15px;text-align: left;margin-bottom: 15px;"> <strong style="font-size: 16px;text-align: justify;"> </strong> </section> <section style="text-align: left;margin-bottom: 15px;margin-top: 15px;"> <strong style="font-size: 16px;"> </strong> </section> <section style="margin-bottom: 15px;"> <strong style="font-size: 16px;"> </strong> </section> <section style="margin-top: 15px;text-align: left;margin-bottom: 15px;"> <strong style="font-size: 16px;"> </strong> </section> <section style="text-align: left;margin-bottom: 15px;"> <strong style="font-size: 16px;"> </strong> </section> <section style="text-align: left;margin-bottom: 15px;"> <strong style="text-align: justify;"> </strong> </section> <section style="text-align: left;margin-bottom: 15px;"> <strong style="font-size: 16px;"></strong> </section> <section style="text-align: left;margin-bottom: 15px;"> <strong style="font-size: 16px;"></strong> </section> <section style="text-align: left;margin-bottom: 15px;"> <strong style="font-size: 16px;"></strong> </section> <section style="text-align: left;margin-bottom: 15px;"> <strong style="font-size: 16px;"></strong> </section> <section style="margin-bottom: 10px;"> <strong style="font-size: 15px;"></strong> </section> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzkyNTI5NTQ1NQ==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/wxcY9TH8dPsYAnrjaZktBe0iahF8ic9QkF26cAw8pK6HPR1bfFEImdyJspvkQvQwmnYxP4eEVW60ewVVickcWXnrQ/0?wx_fmt=png" data-nickname="架构文摘" data-alias="ArchDigest" data-signature="每天一篇架构领域重磅好文,涉及一线互联网公司应用架构(高可用、高性能、高稳定)、大数据、机器学习、Java架构等各个热门领域。" data-from="0"></mpprofile> </section> <p data-tool="mdnice编辑器" style="margin: 10px 1px;padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: PingFangSC-Light;font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.2em;visibility: visible;"><strong style="outline: 0px;color: rgb(14, 136, 235);visibility: visible;">git</strong>对于大家应该都不太陌生,熟练使用git已经成为程序员的一项基本技能,尽管在工作中有诸如 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;outline: 0px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;visibility: visible;">Sourcetree</code>这样牛X的客户端工具,使得合并代码变的很方便。但找工作面试和一些需彰显个人实力的场景,仍然需要我们掌握足够多的git命令。<br style="outline: 0px;visibility: visible;"></p> <p data-tool="mdnice编辑器" style="margin: 10px 1px;padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: PingFangSC-Light;font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.2em;visibility: visible;">下边我们整理了45个日常用git合代码的经典操作场景,基本覆盖了工作中的需求。<br style="outline: 0px;visibility: visible;"></p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 18px;font-family: PingFangSC-Light;text-align: left;background-color: rgb(255, 255, 255);color: rgb(14, 136, 235);visibility: visible;">我刚才提交了什么?</h3> <p data-tool="mdnice编辑器" style="margin: 10px 1px;padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: PingFangSC-Light;font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.2em;visibility: visible;">如果你用 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;outline: 0px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;visibility: visible;">git commit -a</code> 提交了一次变化(changes),而你又不确定到底这次提交了哪些内容。你就可以用下面的命令显示当前<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;outline: 0px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;visibility: visible;">HEAD</code>上的最近一次的提交(commit):</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;color: rgb(0, 0, 0);font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;visibility: visible;"><span style="margin-bottom: -7px;outline: 0px;display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/CJ35Z2cnZA3Dv8nvz8jxc98rlJn3wbXBTBW4sfjHb4YnwyTJHbhMbWVX0WmgojkeEvpiaeMKYCOfSBt6CngIZic1rdpWcZVNML/640?wx_fmt=svg&random=0.4856977753183036") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 674.6px;border-radius: 5px;visibility: visible;"></span><code style="padding: 15px 16px 16px;outline: 0px;overflow-x: auto;color: rgb(171, 178, 191);display: -webkit-box;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;">(main)$ git show<br style="outline: 0px;"></code></pre> <p data-tool="mdnice编辑器" style="margin: 10px 1px;padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: PingFangSC-Light;font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.2em;">或者</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;color: rgb(0, 0, 0);font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="margin-bottom: -7px;outline: 0px;display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/CJ35Z2cnZA3Dv8nvz8jxc98rlJn3wbXBTBW4sfjHb4YnwyTJHbhMbWVX0WmgojkeEvpiaeMKYCOfSBt6CngIZic1rdpWcZVNML/640?wx_fmt=svg&random=0.9857773314583018") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 674.6px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;outline: 0px;overflow-x: auto;color: rgb(171, 178, 191);display: -webkit-box;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;">$ git <span style="outline: 0px;color: rgb(230, 192, 123);line-height: 26px;">log</span> -n1 -p<br style="outline: 0px;"></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 18px;font-family: PingFangSC-Light;text-align: left;background-color: rgb(255, 255, 255);color: rgb(14, 136, 235);">我的提交信息(commit message)写错了</h3> <p data-tool="mdnice编辑器" style="margin: 10px 1px;padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: PingFangSC-Light;font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.2em;">如果你的提交信息(commit message)写错了且这次提交(commit)还没有推(push), 你可以通过下面的方法来修改提交信息(commit message):</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;color: rgb(0, 0, 0);font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="margin-bottom: -7px;outline: 0px;display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/CJ35Z2cnZA3Dv8nvz8jxc98rlJn3wbXBTBW4sfjHb4YnwyTJHbhMbWVX0WmgojkeEvpiaeMKYCOfSBt6CngIZic1rdpWcZVNML/640?wx_fmt=svg&random=0.6361532373555803") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 674.6px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;outline: 0px;overflow-x: auto;color: rgb(171, 178, 191);display: -webkit-box;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;">$ git commit --amend --only<br style="outline: 0px;"></code></pre> <p data-tool="mdnice编辑器" style="margin: 10px 1px;padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: PingFangSC-Light;font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.2em;">这会打开你的默认编辑器, 在这里你可以编辑信息. 另一方面, 你也可以用一条命令一次完成:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;color: rgb(0, 0, 0);font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="margin-bottom: -7px;outline: 0px;display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/CJ35Z2cnZA3Dv8nvz8jxc98rlJn3wbXBTBW4sfjHb4YnwyTJHbhMbWVX0WmgojkeEvpiaeMKYCOfSBt6CngIZic1rdpWcZVNML/640?wx_fmt=svg&random=0.05648735955182871") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 674.6px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;outline: 0px;overflow-x: auto;color: rgb(171, 178, 191);display: -webkit-box;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;">$ git commit --amend --only -m <span style="outline: 0px;color: rgb(152, 195, 121);line-height: 26px;">'xxxxxxx'</span><br style="outline: 0px;"></code></pre> <p data-tool="mdnice编辑器" style="margin: 10px 1px;padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: PingFangSC-Light;font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.2em;">如果你已经推(push)了这次提交(commit), 你可以修改这次提交(commit)然后强推(force push), 但是不推荐这么做。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 18px;font-family: PingFangSC-Light;text-align: left;background-color: rgb(255, 255, 255);color: rgb(14, 136, 235);">我提交(commit)里的用户名和邮箱不对</h3> <p data-tool="mdnice编辑器" style="margin: 10px 1px;padding-top: 8px;padding-bottom: 8px;outline: 0px;color: rgb(0, 0, 0);font-family: PingFangSC-Light;font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.2em;">如果这只是单个提交(commit),修改它:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;color: rgb(0, 0, 0);font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="margin-bottom: -7px;outline: 0px;display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/CJ35Z2cnZA3Dv8nvz8jxc98rlJn3wbXBTBW4sfjHb4YnwyTJHbhMbWVX0WmgojkeEvpiaeMKYCOfSBt6CngIZic1rdpWcZVNML/640?wx_fmt=svg&random=0.46368668699046367") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 674.6px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;outline: 0px;overflow-x: auto;color: rgb(171, 178, 191);display: -webkit-box;font-family: "Operator Mono", Consolas, Monaco, M
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;text-align: left;padding: 5px;font-size: 16px;color: rgb(53, 53, 53);word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;" 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;">在 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">Spring Boot</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@EnableXXX</code>来激活我们某一个功能性的模块,通过类注解激活后我们就能使用所激活的配置给我们带来的功能。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">今天我们就来探究一下这个 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@EnableXXX</code>给我们做了哪些工作,或者我们应该怎么通过自定义的方式开发我们自己的功能模块。</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><span></span></h2> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> IntelliJ IDEA 2020.2.1 (Community Edition) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Maven 3.5.4 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Spring Boot 2.1.1.RELEASE </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);">走进源码</span><span></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;">在 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">SpringBoot</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@Enable</code>的实现方式用两种。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">一种是注解驱动的方式,我们以 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@EnableWebMvc</code>为例进行探究;</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">另外一种是接口编程的方式,我们以 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@EnableCaching</code>为例进行探究。</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、注解驱动方式(<code>@EnableWebMvc</code>)</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">在 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">Spring Boot</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@EnableWebMvc</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">Spring MVC</code>相关的配置,接下来进入源码一探究竟。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #4078f2;line-height: 26px;">@Retention</span>(RetentionPolicy.RUNTIME)<br><span style="color: #4078f2;line-height: 26px;">@Target</span>(ElementType.TYPE)<br><span style="color: #4078f2;line-height: 26px;">@Documented</span><br><span style="color: #4078f2;line-height: 26px;">@Import</span>(DelegatingWebMvcConfiguration<span style="line-height: 26px;">.<span style="color: #a626a4;line-height: 26px;">class</span>)<br><span style="color: #c18401;line-height: 26px;">public</span> @<span style="color: #c18401;line-height: 26px;">interface</span> <span style="color: #c18401;line-height: 26px;">EnableWebMvc</span> </span>{<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">通过观察上面的源码,我们就可以大胆的猜测,其实使用 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@EnableWebMvc</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">DelegatingWebMvcConfiguration.class</code>这个类,接下来我们就进入这个类看看。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #4078f2;line-height: 26px;">@Configuration</span><br><span style="color: #a626a4;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">class</span> <span style="color: #c18401;line-height: 26px;">DelegatingWebMvcConfiguration</span> <span style="color: #a626a4;line-height: 26px;">extends</span> <span style="color: #c18401;line-height: 26px;">WebMvcConfigurationSupport</span> </span>{<br><br> ........<br> <span style="color: #4078f2;line-height: 26px;">@Override</span><br> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">protected</span> <span style="color: #a626a4;line-height: 26px;">void</span> <span style="color: #4078f2;line-height: 26px;">addInterceptors</span><span style="line-height: 26px;">(InterceptorRegistry registry)</span> </span>{<br> <span style="color: #a626a4;line-height: 26px;">this</span>.configurers.addInterceptors(registry);<br> }<br><br> <span style="color: #4078f2;line-height: 26px;">@Override</span><br> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">protected</span> <span style="color: #a626a4;line-height: 26px;">void</span> <span style="color: #4078f2;line-height: 26px;">addResourceHandlers</span><span style="line-height: 26px;">(ResourceHandlerRegistry registry)</span> </span>{<br> <span style="color: #a626a4;line-height: 26px;">this</span>.configurers.addResourceHandlers(registry);<br> }<br> ........<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">进入到这个类中我们发现了这个 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@Configuration</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">DelegatingWebMvcConfiguration</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">WebMvcConfigurationSupport</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">WebMvc</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">Spring</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">WebMvc</code>模块。</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、接口编程的方式(<code>@EnableCaching</code>)</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">在 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">Spring Boot</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@EnableCaching</code>注解用来激活我们的缓存相关的配置,接着进入源码看看到底做了什么。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #4078f2;line-height: 26px;">@Target</span>(ElementType.TYPE)<br><span style="color: #4078f2;line-height: 26px;">@Retention</span>(RetentionPolicy.RUNTIME)<br><span style="color: #4078f2;line-height: 26px;">@Documented</span><br><span style="color: #4078f2;line-height: 26px;">@Import</span>(CachingConfigurationSelector<span style="line-height: 26px;">.<span style="color: #a626a4;line-height: 26px;">class</span>)<br><span style="color: #c18401;line-height: 26px;">public</span> @<span style="color: #c18401;line-height: 26px;">interface</span> <span style="color: #c18401;line-height: 26px;">EnableCaching</span> </span>{<br><br> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">boolean</span> <span style="color: #4078f2;line-height: 26px;">proxyTargetClass</span><span style="line-height: 26px;">()</span> <span style="color: #a626a4;line-height: 26px;">default</span> <span style="color: #a626a4;line-height: 26px;">false</span></span>;<br> <span style="line-height: 26px;">AdviceMode <span style="color: #4078f2;line-height: 26px;">mode</span><span style="line-height: 26px;">()</span> <span style="color: #a626a4;line-height: 26px;">default</span> AdviceMode.PROXY</span>;<br> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">int</span> <span style="color: #4078f2;line-height: 26px;">order</span><span style="line-height: 26px;">()</span> <span style="color: #a626a4;line-height: 26px;">default</span> Ordered.LOWEST_PRECEDENCE</span>;<br><br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这里 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@EnableCaching</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@Import</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">CachingConfigurationSelector</code>,接着我进入这个类看一看。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #a626a4;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">class</span> <span style="color: #c18401;line-height: 26px;">CachingConfigurationSelector</span> <span style="color: #a626a4;line-height: 26px;">extends</span> <span style="color: #c18401;line-height: 26px;">AdviceModeImportSelector</span><<span style="color: #c18401;line-height: 26px;">EnableCaching</span>> </span>{<br><br> .....<br> <br> <span style="color: #4078f2;line-height: 26px;">@Override</span><br> <span style="color: #a626a4;line-height: 26px;">public</span> String[] selectImports(AdviceMode adviceMode) {<br> <span style="color: #a626a4;line-height: 26px;">switch</span> (adviceMode) {<br> <span style="color: #a626a4;line-height: 26px;">case</span> PROXY:<br> <span style="color: #a626a4;line-height: 26px;">return</span> getProxyImports();<br> <span style="color: #a626a4;line-height: 26px;">case</span> ASPECTJ:<br> <span style="color: #a626a4;line-height: 26px;">return</span> getAspectJImports();<br> <span style="color: #a626a4;line-height: 26px;">default</span>:<br> <span style="color: #a626a4;line-height: 26px;">return</span> <span style="color: #a626a4;line-height: 26px;">null</span>;<br> }<br> }<br> .....<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">发现其实这个类没有被注解标注,但是它继承了 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">AdviceModeImportSelector<enablecaching></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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">ImportSelector</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">ImportSelector</code>的代码:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #a626a4;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">interface</span> <span style="color: #c18401;line-height: 26px;">ImportSelector</span> </span>{<br><br> <span style="color: #a0a1a7;font-style: italic;line-height: 26px;">/**<br> * Select and return the names of which class(es) should be imported based on<br> * the {<span style="color: #a626a4;line-height: 26px;">@link</span> AnnotationMetadata} of the importing @{<span style="color: #a626a4;line-height: 26px;">@link</span> Configuration} class.<br> */</span><br> String[] selectImports(AnnotationMetadata importingClassMetadata);<br><br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这个类中只用一个方法,那就是 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">selectImports</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">String[]</code>里面存放的是所有复合条件的配置类的<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><span></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;">通过上面的分析我们已经完成了对 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@EnableXXX</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">Spirng Boot</code>的项目,这里我已经准备好了。</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、注解驱动方式的自定义实现</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">根据我们分析源码的步骤我们首先需要准备一个配置类。接下来在 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">configuration</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">HelloConfiguration</code>。代码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #a0a1a7;font-style: italic;line-height: 26px;">/**<br> * Hello模块的配置<br> */</span><br><span style="color: #4078f2;line-height: 26px;">@Configuration</span><br><span style="color: #a626a4;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">class</span> <span style="color: #c18401;line-height: 26px;">HelloConfiguration</span> </span>{<br><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> String <span style="color: #4078f2;line-height: 26px;">hello</span><span style="line-height: 26px;">()</span> </span>{ <span style="color: #a0a1a7;font-style: italic;line-height: 26px;">// method name is bean name</span><br> System.out.println(<span style="color: #50a14f;line-height: 26px;">"Bean : hello is loading."</span>);<br> <span style="color: #a626a4;line-height: 26px;">return</span> <span style="color: #50a14f;line-height: 26px;">"hello word !"</span>;<br> }<br><br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这里被 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@Bean</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">bean</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">bean</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">Bean : hello is loading.</code>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">配置类我们已经准备好了,接下来我们在 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">annotation</code>包中编写激活配置的注解。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #a0a1a7;font-style: italic;line-height: 26px;">/**<br> * 激活Hello模块配置<br> *<br> * <span style="color: #a626a4;line-height: 26px;">@author</span> Jerome Zhu<br> */</span><br><span style="color: #4078f2;line-height: 26px;">@Retention</span>(RetentionPolicy.RUNTIME)<br><span style="color: #4078f2;line-height: 26px;">@Target</span>(ElementType.TYPE)<br><span style="color: #4078f2;line-height: 26px;">@Documented</span><br><span style="color: #4078f2;line-height: 26px;">@Import</span>(HelloConfiguration<span style="line-height: 26px;">.<span style="color: #a626a4;line-height: 26px;">class</span>) // 模块装配:注解驱动实现<br><span style="color: #c18401;line-height: 26px;">public</span> @<span style="color: #c18401;line-height: 26px;">interface</span> <span style="color: #c18401;line-height: 26px;">EnableHello</span> </span>{<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">最后我们在 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">bootstrap</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@EnableHello</code>模块的启动类。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #a0a1a7;font-style: italic;line-height: 26px;">/**<br> * 验证自定义 {<span style="color: #a626a4;line-height: 26px;">@link</span> EnableHello} 模块化装配<br> *<br> * <span style="color: #a626a4;line-height: 26px;">@author</span> Jerome Zhu<br> */</span><br><span style="color: #4078f2;line-height: 26px;">@EnableHello</span><br><span style="color: #a626a4;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">class</span> <span style="color: #c18401;line-height: 26px;">EnableHelloBootstrap</span> </span>{<br><br> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span> <span style="color: #a626a4;line-height: 26px;">static</span> <span style="color: #a626a4;line-height: 26px;">void</span> <span style="color: #4078f2;line-height: 26px;">main</span><span style="line-height: 26px;">(String[] args)</span> </span>{<br> ConfigurableApplicationContext context = <span style="color: #a626a4;line-height: 26px;">new</span> SpringApplicationBuilder(EnableHelloBootstrap<span style="line-height: 26px;">.<span style="color: #a626a4;line-height: 26px;">class</span>)<br> .<span style="color: #c18401;line-height: 26px;">web</span>(<span style="color: #c18401;line-height: 26px;">WebApplicationType</span>.<span style="color: #c18401;line-height: 26px;">NONE</span>)<br> .<span style="color: #c18401;line-height: 26px;">run</span>(<span style="color: #c18401;line-height: 26px;">args</span>)</span>;<br><br> String helloBean = context.getBean(<span style="color: #50a14f;line-height: 26px;">"hello"</span>, String<span style="line-height: 26px;">.<span style="color: #a626a4;line-height: 26px;">class</span>)</span>;<br> System.out.println(<span style="color: #50a14f;line-height: 26px;">"hello Bean: "</span> + helloBean);<br> context.close();<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">我们在我们启动类上标注了 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@EnableHello</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">Hello</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">Spring Boot</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">ConfigurableApplicationContext</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">bean</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">hello</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">bean</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">bean</code>的内容,最后关闭上下文。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">我们启动程序后,可以在控制台中看到这样两行输出:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">Bean : hello is loading.<br>hello Bean: hello word !<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这刚好就是我们配置的内容,到这儿我们就完成了基于注解驱动方式激活(启动)配置。</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、接口编程方式自定义实现</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">根据我们读过源码后,我们首先最重要的是有一个继承 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">ImportSelector</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">annotation</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">HelloImportSelector</code>配置类。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #a0a1a7;font-style: italic;line-height: 26px;">/**<br> * Hello {<span style="color: #a626a4;line-height: 26px;">@link</span> ImportSelector} 的实现<br> */</span><br><span style="color: #a626a4;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">class</span> <span style="color: #c18401;line-height: 26px;">HelloImportSelector</span> <span style="color: #a626a4;line-height: 26px;">implements</span> <span style="color: #c18401;line-height: 26px;">ImportSelector</span> </span>{<br><br> <span style="color: #a626a4;line-height: 26px;">private</span> <span style="color: #a626a4;line-height: 26px;">final</span> String key = <span style="color: #50a14f;line-height: 26px;">"jerome"</span>;<br><br> <span style="color: #4078f2;line-height: 26px;">@Override</span><br> <span style="color: #a626a4;line-height: 26px;">public</span> String[] selectImports(AnnotationMetadata importingClassMetadata) {<br><br> <span style="color: #a626a4;line-height: 26px;">if</span> (<span style="color: #50a14f;line-height: 26px;">"jerome"</span>.equals(key)) {<br> <span style="color: #a626a4;line-height: 26px;">return</span> <span style="color: #a626a4;line-height: 26px;">new</span> String[]{HelloJeromeConfiguration<span style="line-height: 26px;">.<span style="color: #a626a4;line-height: 26px;">class</span>.<span style="color: #c18401;line-height: 26px;">getName</span>()}</span>;<br> }<br><br> <span style="color: #a626a4;line-height: 26px;">return</span> <span style="color: #a626a4;line-height: 26px;">new</span> String[]{HelloConfiguration<span style="line-height: 26px;">.<span style="color: #a626a4;line-height: 26px;">class</span>.<span style="color: #c18401;line-height: 26px;">getName</span>()}</span>;<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这里为了体现出 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">selectImports</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">jerome</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">HelloJeromeConfiguration</code>这个配置类。首先看一个这个配置类的内容。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #a0a1a7;font-style: italic;line-height: 26px;">/**<br> * Hello模块的配置<br> *<br> * <span style="color: #a626a4;line-height: 26px;">@author</span> Jerome Zhu<br> */</span><br><span style="color: #4078f2;line-height: 26px;">@Configuration</span><br><span style="color: #a626a4;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">class</span> <span style="color: #c18401;line-height: 26px;">HelloJeromeConfiguration</span> </span>{<br><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> String <span style="color: #4078f2;line-height: 26px;">hello</span><span style="line-height: 26px;">()</span> </span>{ <span style="color: #a0a1a7;font-style: italic;line-height: 26px;">// method name is bean name</span><br> System.out.println(<span style="color: #50a14f;line-height: 26px;">"Bean : hello is loading."</span>);<br> <span style="color: #a626a4;line-height: 26px;">return</span> <span style="color: #50a14f;line-height: 26px;">"hello jerome !"</span>;<br> }<br><br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">加载这个配置类后 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">bean</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">hello</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">hello jerome !</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@EnableHello</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@EnableHellos</code>。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #a0a1a7;font-style: italic;line-height: 26px;">/**<br> * 激活Hellos模块配置<br> *<br> * <span style="color: #a626a4;line-height: 26px;">@author</span> Jerome Zhu<br> */</span><br><span style="color: #4078f2;line-height: 26px;">@Retention</span>(RetentionPolicy.RUNTIME)<br><span style="color: #4078f2;line-height: 26px;">@Target</span>(ElementType.TYPE)<br><span style="color: #4078f2;line-height: 26px;">@Documented</span><br><span style="color: #4078f2;line-height: 26px;">@Import</span>(HelloImportSelector<span style="line-height: 26px;">.<span style="color: #a626a4;line-height: 26px;">class</span>) // 模块装配:接口驱动实现 优点可选<span style="color: #c18401;line-height: 26px;">bean</span><br><span style="color: #c18401;line-height: 26px;">public</span> @<span style="color: #c18401;line-height: 26px;">interface</span> <span style="color: #c18401;line-height: 26px;">EnableHellos</span> </span>{<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这里使用了 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">HelloImportSelector</code>来实现我们的模块装配。</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <span style="display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;font-size: 16px;margin-right: 10px;margin-left: 10px;">这里 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@EnableHellos</code>可能不符合命名规范,这里只做演示使用,不要喷我。</p> <span style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;">”</span> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">最后我们在 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">bootstrap</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@EnableHello</code>模块的启动类。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #a0a1a7;font-style: italic;line-height: 26px;">/**<br> * 验证自定义 {<span style="color: #a626a4;line-height: 26px;">@link</span> EnableHellos} 模块化装配<br> *<br> * <span style="color: #a626a4;line-height: 26px;">@author</span> Jerome Zhu<br> */</span><br><span style="color: #4078f2;line-height: 26px;">@EnableHellos</span><br><span style="color: #a626a4;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">class</span> <span style="color: #c18401;line-height: 26px;">EnableHellosBootstrap</span> </span>{<br><br> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span> <span style="color: #a626a4;line-height: 26px;">static</span> <span style="color: #a626a4;line-height: 26px;">void</span> <span style="color: #4078f2;line-height: 26px;">main</span><span style="line-height: 26px;">(String[] args)</span> </span>{<br> ConfigurableApplicationContext context = <span style="color: #a626a4;line-height: 26px;">new</span> SpringApplicationBuilder(EnableHellosBootstrap<span style="line-height: 26px;">.<span style="color: #a626a4;line-height: 26px;">class</span>)<br> .<span style="color: #c18401;line-height: 26px;">web</span>(<span style="color: #c18401;line-height: 26px;">WebApplicationType</span>.<span style="color: #c18401;line-height: 26px;">NONE</span>)<br> .<span style="color: #c18401;line-height: 26px;">run</span>(<span style="color: #c18401;line-height: 26px;">args</span>)</span>;<br><br> String helloBean = context.getBean(<span style="color: #50a14f;line-height: 26px;">"hello"</span>, String<span style="line-height: 26px;">.<span style="color: #a626a4;line-height: 26px;">class</span>)</span>;<br> System.out.println(<span style="color: #50a14f;line-height: 26px;">"hello Bean: "</span> + helloBean);<br> context.close();<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这里和基于注解驱动方式激活(启动)配置的验证方法一样,我就是直接拷贝的,主要修改了 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@EnableHellos</code>这个激活注解。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">我们启动程序后,可以在控制台中看到这样两行输出:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">Bean : hello is loading.<br>hello Bean: hello jerome !<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这刚好就是我们配置的内容,到这儿我们就完成了基于接口编程方式激活(启动)配置。</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><span></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;">我们通过上面了解了 <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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@EnableXXX</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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">@Enable***</code>的注解,来手动激活配置,这种方式在某些场景并不是很方便。</p> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;outline: 0px;border-width: initial;border-style: none;border-color: initial;color: rgb(53, 53, 53);font-size: 0.9em;white-space: normal;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;overflow: auto;line-height: 1.75;border-radius: 13px;background: rgb(245, 245, 245);"> <p style="margin-right: 10px;margin-left: 10px;padding-top: 8px;padding-bottom: 8px;outline: 0px;line-height: 26px;font-size: 16px;">此文已收录至公众号同名博客,https://javadaily.cn,可点击阅读原文查看。</p> </blockquote> <hr data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;white-space: normal;color: rgb(53, 53, 53);font-size: 16px;letter-spacing: 0.8px;word-spacing: 0.8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;background-color: rgb(255, 255, 255);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));"> </section>
作者:微信小助手
<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, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">做为一名程序员,发展方向大致可以分为两个方面:一个是业务架构,一个是技术架构(中间件方向)。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">业务架构,取其核心关键词,主要是围绕这不同的业务场景、业务规则,完成业务系统的落地建设,为用户提供在线化的信息服务。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">既然说到业务,那方向可就多了去了,如:出行、外卖、充电宝、O2O、内容、社交、生鲜、电商,不同的业务有不同的特点。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">面对这么多的业务域,有没有通用技术经验可以抽取,让我们可以<strong style="font-weight: border;color: #0e88eb;">以一应百</strong> 。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">这里,首推电商业务,电商系统的复杂性很高,对<strong style="font-weight: border;color: #0e88eb;">高并发</strong> 、<strong style="font-weight: border;color: #0e88eb;">高性能</strong> 、<strong style="font-weight: border;color: #0e88eb;">高可用</strong> 、<strong style="font-weight: border;color: #0e88eb;">高扩展</strong> ,等方面要求很高。你在其他业务中可能遇到的问题,在电商系统中基本都会遇到。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">作为开发,希望自己成为某几个业务领域的<strong style="font-weight: border;color: #0e88eb;">技术专家</strong> ,最好能先精通<strong style="font-weight: border;color: #0e88eb;">电商领域</strong> ,有很强的借鉴意义。对于你后续拓展熟悉其他业务领域的个性化玩法有很大帮助。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">那么,电商领域的技术架构有哪些常见问题?</strong></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&mid=2247487551&idx=1&sn=18f64ba49f3f0f9d8be9d1fdef8857d9&scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 20px 41.8542px;right: auto;bottom: auto;width: 100%;"><img class="rich_pages wxw-img" data-ratio="0.5388888888888889" src="/upload/e307e181a3ba29a706c9c24566b3da0b.jpg" data-type="jpeg" data-w="1080" style="border-radius: 0px 0px 5px 5px;display: block;margin: 0px;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"></span></a> </figure> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-family: STHeitiSC-Light;color: rgb(14, 136, 235);font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(14, 136, 235);"><a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&mid=2247487551&idx=1&sn=18f64ba49f3f0f9d8be9d1fdef8857d9&scene=21#wechat_redirect" style="color: rgb(14, 136, 235);border-bottom: 0px solid rgb(255, 53, 2);" data-linktype="2">一、避免重复下单</a></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">用户快速点了两次 “提交订单” 按钮,浏览器会向后端发送两条创建订单的请求,最终会创建两条一模一样的订单。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">解决方案:</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">解决方案就是采用<strong style="font-weight: border;color: #0e88eb;">幂等机制</strong> ,多次请求和一次请求产生的效果是一样的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">方案一:</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">利用数据库自身特性 “主键唯一约束”,在插入订单记录时,带上主键值,如果订单重复,记录插入会失败。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">操作过程:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 引入一个服务,用于生成一个“全局唯一的订单号” </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 进入创建订单页面时,前端请求该服务,预生成订单ID </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 提交订单时,请求参数除了业务参数外,还要带上这个预生成订单ID </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">方案二:</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">前端通过js脚本控制,无法解决用户刷新提交的请求。另外也无法解决恶意提交。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">不建议采用该方案,如果想用,也只是作为一个补充方案。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">方案三:</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">前后约定附加参数校验。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">当用户点击购买按钮时,渲染下单页面,展示商品、收货地址、运费、价格等信息,同时页面会埋上<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Token </code>信息,用户提交订单时,后端业务逻辑会校验token,有且匹配才认为是合理请求。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">注意:同一个 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Token</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;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG2kREVLZKwASrGcibrwsccTKqSiacTyLzVLIJHT7GibWRwWEz0cnoDgkovfQWlTDVEZHd5h8w3MaDlmb6NxDuGhG1J/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></spa
作者:微信小助手
<section data-mpa-template="t" mpa-from-tpl="t" data-mpa-powered-by="yiban.io"> <section data-mpa-template="t" mpa-from-tpl="t"> <p style="clear: both;min-height: 1em;color: rgb(51, 51, 51);font-size: 17px;letter-spacing: 0.544px;text-align: center;"><br></p> </section> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding: 0px 0.5em;line-height: 1.6;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 15px;letter-spacing: 0.05em;color: rgb(89, 89, 89);"> <h2 data-tool="mdnice编辑器" style="min-height: 32px;line-height: 28px;color: rgb(119, 48, 152);border-bottom: 1px solid rgb(119, 48, 152);border-top-color: rgb(119, 48, 152);border-right-color: rgb(119, 48, 152);border-left-color: rgb(119, 48, 152);font-size: 22px;margin: 1em auto;padding-top: 0.5em;padding-bottom: 0.5em;text-align: center;width: 85%;font-weight: bold;display: flex;flex-direction: column;justify-content: center;"><span style="display: none;"></span>前言</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><span style="letter-spacing: 0.05em;">这篇文章主要介绍一些目前主流的</span><span style="letter-spacing: 0.05em;">几种分布式解决方案以及阿里开源的一站式分布式解决方案Seata。</span><br></p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="letter-spacing: 0.05em;color: rgb(119, 48, 152);">文章有点长,耐心看完,看完你还不懂分布式事务,欢迎来捶我......</strong></p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">文章目录如下:<br></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;padding: 0px 0.5em;"> <img class="rich_pages wxw-img" data-fileid="100015719" data-ratio="0.44015696533682147" src="/upload/c212012e7a5033037922402bb2898afc.png" data-type="png" data-w="1529" style="display: block;margin-right: auto;margin-left: auto;border-radius: 3px;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;"> </figure> <h2 data-tool="mdnice编辑器" style="min-height: 32px;line-height: 28px;color: rgb(119, 48, 152);border-bottom: 1px solid rgb(119, 48, 152);border-top-color: rgb(119, 48, 152);border-right-color: rgb(119, 48, 152);border-left-color: rgb(119, 48, 152);font-size: 22px;margin: 1em auto;padding-top: 0.5em;padding-bottom: 0.5em;text-align: center;width: 85%;font-weight: bold;display: flex;flex-direction: column;justify-content: center;"><span style="display: none;"></span>什么是分布式事务?</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">分布式对应的是单体架构,互联网早起单体架构是非常流行的,好像是一个家族企业,大家在一个家里劳作,单体架构如下图:</p> <img class="rich_pages wxw-img" data-fileid="100015718" data-ratio="0.9118993135011442" src="/upload/685cd3e95a757f39cd95b9badbbc3c5b.png" data-type="png" data-w="874" style="display: block;margin-right: auto;margin-left: auto;zoom: 70%;border-radius: 3px;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;"> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">但是随着业务的复杂度提高,大家族人手不够,此时不得不招人,这样逐渐演变出了分布式服务,互相协作,每个服务负责不同的业务,架构如下图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;padding: 0px 0.5em;"> <img class="rich_pages wxw-img" data-fileid="100015720" data-ratio="0.563858695652174" src="/upload/40664cfccfbb0036f96deec976c77b75.png" data-type="png" data-w="736" style="display: block;margin-right: auto;margin-left: auto;border-radius: 3px;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> 分布式架构 </figcaption> </figure> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">因此需要服务与服务之间的远程协作才能完成事务,这种分布式系统环境下由不同的服务之间通过网络远程协作完成事务称之为分布式事务,例如用户注册送积分 事务、创建订单减库存事务,银行转账事务等都是分布式事务。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">典型的场景就是微服务架构 微服务之间通过远程调用完成事务操作。比如:<strong style="color: rgb(119, 48, 152);">订单微服务</strong>和<strong style="color: rgb(119, 48, 152);">库存微服务</strong>,下单的同时订单微服务请求库存微服务减库存。简言之:<strong style="color: rgb(119, 48, 152);">跨JVM进程产生分布式事务</strong>。</p> <h2 data-tool="mdnice编辑器" style="min-height: 32px;line-height: 28px;color: rgb(119, 48, 152);border-bottom: 1px solid rgb(119, 48, 152);border-top-color: rgb(119, 48, 152);border-right-color: rgb(119, 48, 152);border-left-color: rgb(119, 48, 152);font-size: 22px;margin: 1em auto;padding-top: 0.5em;padding-bottom: 0.5em;text-align: center;width: 85%;font-weight: bold;display: flex;flex-direction: column;justify-content: center;"><span style="display: none;"></span>什么是CAP原则?</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">CAP原则又叫CAP定理,同时又被称作布鲁尔定理(Brewer's theorem),指的是在一个分布式系统中,<strong style="color: rgb(119, 48, 152);">不可能同时满足以下三点</strong>。</p> <img class="rich_pages wxw-img" data-fileid="100015721" data-ratio="0.9375" src="/upload/6f1493ac49f40227b0f508735e26269b.jpg" data-type="jpeg" data-w="720" style="display: block;margin-right: auto;margin-left: auto;zoom: 70%;border-radius: 3px;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;"> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(119, 48, 152);"><span style="display: none;"></span>一致性(Consistency)<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">指强一致性,在写操作完成后开始的任何读操作都必须返回该值,或者后续写操作的结果。</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-bottom: none;font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin: 10px 5px;border-left-color: rgb(150, 84, 181);border-right: 1px solid rgb(150, 84, 181);color: rgb(97, 97, 97);quotes: none;background: rgb(251, 249, 253);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">也就是说,在一致性系统中,一旦客户端将值写入任何一台服务器并获得响应,那么之后client从其他任何服务器读取的都是刚写入的数据</p> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">一致性保证了不管向哪台服务器写入数据,其他的服务器能实时同步数据</p> </blockquote> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(119, 48, 152);"><span style="display: none;"></span>可用性(Availability)<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">可用性(高可用)是指:每次向未崩溃的节点发送请求,总能保证收到响应数据(允许不是最新数据)</p> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(119, 48, 152);"><span style="display: none;"></span>分区容忍性(Partition tolerance)<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">分布式系统在遇到任何网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务,也就是说,服务器<strong style="color: rgb(119, 48, 152);">A</strong>和<strong style="color: rgb(119, 48, 152);">B</strong>发送给对方的任何消息都是可以放弃的,也就是说A和B可能因为各种意外情况,导致无法成功进行同步,分布式系统要能容忍这种情况。除非整个网络环境都发生了故障。</p> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(119, 48, 152);"><span style="display: none;"></span>为什么只能在A和C之间做出取舍?<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">分布式系统中,必须满足 CAP 中的 P,此时只能在 C/A 之间作出取舍。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">如果选择了<strong style="color: rgb(119, 48, 152);">CA</strong>,舍弃了P,说白了就是一个单体架构。</p> <h2 data-tool="mdnice编辑器" style="min-height: 32px;line-height: 28px;color: rgb(119, 48, 152);border-bottom: 1px solid rgb(119, 48, 152);border-top-color: rgb(119, 48, 152);border-right-color: rgb(119, 48, 152);border-left-color: rgb(119, 48, 152);font-size: 22px;margin: 1em auto;padding-top: 0.5em;padding-bottom: 0.5em;text-align: center;width: 85%;font-weight: bold;display: flex;flex-direction: column;justify-content: center;"><span style="display: none;"></span>一致性有几种分类?</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">CAP理论告诉我们只能在C、A之间选择,在分布式事务的最终解决方案中一般选择牺牲一致性来获取可用性和分区容错性。</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-bottom: none;font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin: 10px 5px;border-left-color: rgb(150, 84, 181);border-right: 1px solid rgb(150, 84, 181);color: rgb(97, 97, 97);quotes: none;background: rgb(251, 249, 253);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">这里的 “牺牲一致性” 并不是完全放弃数据的一致性,而是放弃<strong style="color: rgb(119, 48, 152);">强一致性</strong>而换取<strong style="color: rgb(119, 48, 152);">弱一致性</strong>。</p> </blockquote> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">一致性可以分为以下三种:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-1"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 强一致性 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 弱一致性 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 最终一致性 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(119, 48, 152);"><span style="display: none;"></span>强一致性<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">系统中的某个数据被成功更新后,后续任何对该数据的读取操作都将得到更新后的值。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">也称为:原子一致性(Atomic Consistency)、线性一致性(Linearizable Consistency)</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">简言之,在任意时刻,所有节点中的数据是一样的。例如,对于关系型数据库,要求更新过的数据能被后续的访问都能看到,这是强一致性。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(119, 48, 152);">总结</strong>:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-1"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 一个集群需要对外部提供强一致性,所以只要集群内部某一台服务器的数据发生了改变,那么就需要等待集群内其他服务器的数据同步完成后,才能正常的对外提供服务。 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 保证了强一致性,务必会损耗 <strong style="color: rgb(119, 48, 152);">可用性</strong>。 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(119, 48, 152);"><span style="display: none;"></span>弱一致性<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">系统中的某个数据被更新后,后续对该数据的读取操作<strong style="color: rgb(119, 48, 152);">可能</strong>得到更新后的值,也可能是更改前的值。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">但即使过了<strong style="color: rgb(119, 48, 152);">不一致时间窗口</strong>这段时间后,后续对该数据的读取也不一定是最新值。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">所以说,可以理解为数据更新后,如果能容忍后续的访问只能访问到部分或者全部访问不到,则是弱一致性。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">例如12306买火车票,虽然最后看到还剩下几张余票,但是只要选择购买就会提示没票了,这就是弱一致性。</p> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(119, 48, 152);"><span style="display: none;"></span>最终一致性<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color:
作者:微信小助手
<section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzkyNzExODM3OA==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/FibLXRKztelWZcHdUd1gtkSCYxXrd3Hj45GpTLdljGiaykvo8dyHibqO0hIfiad3lqFo7wmoamWfRCPat8HLicm87kw/0?wx_fmt=png" data-nickname="Java仓库" data-alias="" data-signature="专注Java全栈开发,分享实用技术干货。" data-from="0"></mpprofile> </section> <p style="margin-top: 5px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(0, 0, 0);font-size: 16px;text-align: center;line-height: normal;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 10px;letter-spacing: 0.544px;text-align: justify;color: rgb(136, 136, 136);font-family: Optima-Regular, PingFangTC-light;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">来源:blog.csdn.net/wenwenaier?type=blog</span></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;outline: 0px;max-width: 100%;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;color: black;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Roboto, Oxygen, Ubuntu, Cantarell, PingFangSC-light, PingFangTC-light, "Open Sans", "Helvetica Neue", sans-serif;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 1.3em;max-width: 100%;border-bottom: 2px solid rgb(239, 112, 96);visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">1. HashMap的底层数据结构是什么?</span><span style="outline: 0px;max-width: 100%;display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;line-height: 26px;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">在JDK1.7中和JDK1.8中有所区别:</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;line-height: 26px;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">在JDK1.7中,由”数组+链表“组成,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;line-height: 26px;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">在JDK1.8中,有“数组+链表+红黑树”组成。当链表过长,则会严重影响HashMap的性能,红黑树搜索时间复杂度是O(logn),而链表是O(n)。因此,JDK1.8对数据结构做了进一步的优化,引入了红黑树,链表和红黑树在达到一定条件会进行转换:</p> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;outline: 0px;max-width: 100%;visibility: visible;overflow-wrap: break-word !important;"> <li style="outline: 0px;max-width: 100%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 当链表超过8且数组长度(数据总量)超过64才会转为红黑树 </section></li> <li style="outline: 0px;max-width: 100%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 将链表转换成红黑树前会判断,如果当前数组的长度小于64,那么会选择先进行数组扩容,而不是转换为红黑树,以减少搜索时间。 </section></li> </ul> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img class="rich_pages wxw-img" data-ratio="0.4449901768172888" data-type="png" data-w="1018" src="/upload/37cd0b6410fe8631f018fbb466da8a64.png" style="outline: 0px;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 556px !important;"> </section> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 1.3em;max-width: 100%;border-bottom: 2px solid rgb(239, 112, 96);visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">2. 说一下HashMap的特点</span><span style="outline: 0px;max-width: 100%;display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;"> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> hashmap存取是无序的 </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 键和值位置都可以是null,但是键位置只能是一个null </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 键位置是唯一的,底层的数据结构是控制键的 </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> jdk1.8前数据结构是:链表+数组jdk1.8之后是:数组+链表+红黑树 </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 阈值(边界值)>8并且数组长度大于64,才将链表转换成红黑树,变成红黑树的目的是提高搜索速度,高效查询 </section></li> </ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 1.3em;max-width: 100%;border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">3. 解决hash冲突的办法有哪些?HashMap用的哪种?</span><span style="outline: 0px;max-width: 100%;display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">解决Hash冲突方法有:开放定址法、再哈希法、链地址法(HashMap中常见的拉链法)、简历公共溢出区。HashMap中采用的是链地址法。</p> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;"> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 开放定址法也称为再散列法,基本思想就是,如果p=H(key)出现冲突时,则以p为基础,再次hash,p1=H(p),如果p1再次出现冲突,则以p1为基础,以此类推,直到找到一个不冲突的哈希地址pi。因此开放定址法所需要的hash表的长度要大于等于所需要存放的元素,而且因为存在再次hash,所以只能在删除的节点上做标记,而不能真正删除节点 </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 再哈希法(双重散列,多重散列),提供多个不同的hash函数,R1=H1(key1)发生冲突时,再计算R2=H2(key1),直到没有冲突为止。这样做虽然不易产生堆集,但增加了计算的时间。 </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 链地址法(拉链法),将哈希值相同的元素构成一个同义词的单链表,并将单链表的头指针存放在哈希表的第i个单元中,查找、插入和删除主要在同义词链表中进行,链表法适用于经常进行插入和删除的情况。 </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 建立公共溢出区,将哈希表分为公共表和溢出表,当溢出发生时,将所有溢出数据统一放到溢出区 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">注意开放定址法和再哈希法的区别是</p> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;"> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 开放定址法只能使用同一种hash函数进行再次hash,再哈希法可以调用多种不同的hash函数进行再次hash </section></li> </ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 1.3em;max-width: 100%;border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">4. 为什么要在数组长度大于64之后,链表才会进化为红黑树</span><span style="outline: 0px;max-width: 100%;display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">在数组比较小时如果出现红黑树结构,反而会降低效率,而红黑树需要进行左旋右旋,变色,这些操作来保持平衡,同时数组长度小于64时,搜索时间相对要快些,总之是为了加快搜索速度,提高性能</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">JDK1.8以前HashMap的实现是数组+链表,即使哈希函数取得再好,也很难达到元素百分百均匀分布。当HashMap中有大量的元素都存放在同一个桶中时,这个桶下有一条长长的链表,此时HashMap就相当于单链表,假如单链表有n个元素,遍历的时间复杂度就从O(1)退化成O(n),完全失去了它的优势,为了解决此种情况,JDK1.8中引入了红黑树(查找的时间复杂度为O(logn))来优化这种问题</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 1.3em;max-width: 100%;border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">5. 为什么加载因子设置为0.75,初始化临界值是12?</span><span style="outline: 0px;max-width: 100%;display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">HashMap中的threshold是HashMap所能容纳键值对的最大值。计算公式为length*LoadFactory。也就是说,在数组定义好长度之后,负载因子越大,所能容纳的键值对个数也越大</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">loadFactory越趋近于1,那么数组中存放的数据(entry也就越来越多),数据也就越密集,也就会有更多的链表长度处于更长的数值,我们的查询效率就会越低,当我们添加数据,产生hash冲突的概率也会更高</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">默认的loadFactory是0.75,loadFactory越小,越趋近于0,数组中个存放的数据(entry)也就越少,表现得更加稀疏</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;max-width: 100%;display: flex;flex-direction: column;justify-content: center;align-items: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img class="rich_pages wxw-img" data-ratio="0.6998992950654582" data-type="png" data-w="993" src="/upload/dc323c42aa27410328a9e6c232a2d361.png" style="margin-right: auto;margin-left: auto;outline: 0px;border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);display: block;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: 375.746px !important;visibility: visible !important;width: 536px !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">0.75是对空间和时间效率的一种平衡选择</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">如果负载因子小一些比如是0.4,那么初始长度16*0.4=6,数组占满6个空间就进行扩容,很多空间可能元素很少甚至没有元素,会造成大量的空间被浪费</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">如果负载因子大一些比如是0.9,这样会导致扩容之前查找元素的效率非常低</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">loadfactory设置为0.75是经过多重计算检验得到的可靠值,可以最大程度的减少rehash的次数,避免过多的性能消耗</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 1.3em;max-width: 100%;border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">6. 哈希表底层采用何种算法计算hash值?还有哪些算法可以计算出hash值?</span><span style="outline: 0px;max-width: 100%;display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">hashCode方法是Object中的方法,所有的类都可以对其进行使用,首先底层通过调用hashCode方法生成初始hash值h1,然后将h1无符号右移16位得到h2,之后将h1与h2进行按位异或(^)运算得到最终hash值h3,之后将h3与(length-1)进行按位与(&)运算得到hash表索引</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">其他可以计算出hash值的算法有</p> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;"> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 平方取中法 </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 取余数 </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 伪随机数法 </section></li> </ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 1.3em;max-width: 100%;border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">7. 当两个对象的hashCode相等时会怎样</span><span style="outline: 0px;max-width: 100%;display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">hashCode相等产生hash碰撞,hashCode相等会调用equals方法比较内容是否相等,内容如果相等则会进行覆盖,内容如果不等则会连接到链表后方,链表长度超过8且数组长度超过64,会转变成红黑树节点</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 1.3em;max-width: 100%;border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">8. 何时发生哈希碰撞和什么是哈希碰撞,如何解决哈希碰撞?</span><span style="outline: 0px;max-width: 100%;display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">只要两个元素的key计算的hash码值相同就会发生hash碰撞,jdk8之前使用链表解决哈希碰撞,jdk8之后使用链表+红黑树解决哈希碰撞</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 1.3em;max-width: 100%;border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">9. HashMap的put方法流程</span><span style="outline: 0px;max-width: 100%;display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">以jdk8为例,简要流程如下:</p> <ol data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;"> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 首先根据key的值计算hash值,找到该元素在数组中存储的下标 </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 如果数组是空的,则调用resize进行初始化; </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 如果没有哈希冲突直接放在对应的数组下标里 </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 如果冲突了,且key已经存在,就覆盖掉value </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 如果冲突后是链表结构,就判断该链表是否大于8,如果大于8并且数组容量小于64,就进行扩容;如果链表节点数量大于8并且数组的容量大于64,则将这个结构转换成红黑树;否则,链表插入键值对,若key存在,就覆盖掉value </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: b