文章列表

这款可视化工具,Java 调优起来真的 so easy啊

作者:微信小助手

<section data-tools="新媒体排版" data-id="3356876" data-style-type="" style="white-space: normal;color: black;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);" data-mpa-powered-by="yiban.io"> <p style="text-align: center;"><span style="letter-spacing: 0.544px;">&nbsp;</span><img class="rich_pages" data-ratio="0.18170426065162906" data-s="300,640" data-type="jpeg" data-w="798" src="/upload/fc934a676dcaf231fb5604ba23f6b725.jpg" style="font-size: 14px;letter-spacing: 1px;vertical-align: middle;border-style: none;border-radius: 4px;box-shadow: none;box-sizing: border-box !important;visibility: visible !important;width: 187px !important;"></p> </section> <section style="white-space: normal;color: black;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: left;"> <img class="__bg_gif" data-ratio="0.23416666666666666" src="/upload/2bbe3027dbbac55fe259ab69f077bced.png" data-type="gif" data-w="1200" style="box-sizing: border-box !important;width: 538px !important;visibility: visible !important;">&nbsp; </section> <section style="font-size: 16px;"> <section powered-by="xiumi.us" style="margin-top: 10px;text-align: left;"> <section style="display: inline-block;width: 578px;vertical-align: top;background-position: 0% 0%;background-repeat: repeat;background-size: 1.95228%;background-attachment: scroll;border-width: 1px;border-radius: 0px;border-style: dashed dashed none;border-color: rgb(255, 226, 215);background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/qMicvibdvl7p32BKyoBicibHEyM5nibTGlgSPLGR3l8gR3hia0XwhLj4sHLiaicA4GQtW4Nqh6NxC9eCwUllTtV5vxug5g/640?wx_fmt=png&quot;);"> <section powered-by="xiumi.us" style="margin-top: 10px;margin-bottom: 15px;"> <section style="padding-right: 15px;padding-left: 15px;font-size: 14px;color: rgb(87, 60, 60);line-height: 1.8;letter-spacing: 1.8px;"> <p style="white-space: normal;">本文授权转载自公众号:开发者技术前线</p> <p style="white-space: normal;">原文链接:<span style="letter-spacing: 1.8px;">https://mp.weixin.qq.com/s/Dsqvt8JrtGpcSFLwplo-_w</span></p> </section> </section> </section> </section> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);"> <h1 data-tool="mdnice编辑器" style="margin-top: 38px;margin-bottom: 10px;font-weight: bold;font-size: 24px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;color: black;text-align: center;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/JdLkEI9sZffBdQ2u7mibDAK9aMrPQX92p4QGb38srSbibgab1mxM7o3JnPgzbBQG6VgaIt8z4AR4Z19ib0lKwUhBQ/640?wx_fmt=png&quot;);background-position: center top;background-repeat: no-repeat;background-size: 75px;line-height: 95px;"><span style="font-size: 20px;border-bottom: 2px solid rgb(46, 121, 80);color: rgb(0, 82, 255);">JVisualVM 简介</span></h1> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">VisualVM 是Netbeans的profile子项目,已在JDK6.0 update 7 中自带,能够监控线程,内存情况,查看方法的CPU时间和内存中的对 象,已被GC的对象,反向查看分配的堆栈(如100个String对象分别由哪几个对象分配出来的)。在JDK_HOME/bin(默认是C:\Program Files\Java\jdk1.6.0_13\bin)目录下面,有一个jvisualvm.exe文件,双击打开,从UI上来看,这个软件是基于NetBeans开发的了。<br></p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">VisualVM 提供了一个可视界面,用于查看 Java 虚拟机 (Java Virtual Machine, JVM) 上运行的基于 Java 技术的应用程序的详细信息。VisualVM 对 Java Development Kit (JDK) 工具所检索的 JVM 软件相关数据进行组织,并通过一种使您可以快速查看有关多个 Java 应用程序的数据的方式提供该信息。您可以查看本地应用程序或远程主机上运行的应用程序的相关数据。此外,还可以捕获有关 JVM 软件实例的数据,并将该数据保存到本地系统,以供后期查看或与其他用户共享。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">双击启动 jvisualvm.exe,启动起来后和jconsole 一样同样可以选择本地和远程,如果需要监控远程同样需要配置相关参数。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">主界面如下;</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.6082272282076395" data-type="jpeg" data-w="1021" src="/upload/b74555d797c9c0aab034a63dfdd8953.jpg" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">VisualVM可以根据需要安装不同的插件,每个插件的关注点都不同,有的主要监控GC,有的主要监控内存,有的监控线程等。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.6136114160263447" data-type="jpeg" data-w="911" src="/upload/f29e2a41976565a2825de5a8667b748b.jpg" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">如何安装:</p> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding: 15px 20px;border-left-color: rgb(53, 179, 120);color: rgb(106, 115, 125);font-size: 0.9em;overflow: auto;background: rgb(251, 249, 253);line-height: 27px;"> <p style="line-height: 26px;font-size: 15px;color: rgb(89, 89, 89);">1、从主菜单中选择“工具”&gt;“插件”。2、在“可用插件”标签中,选中该插件的“安装”复选框。单击“安装”。3、逐步完成插件安装程序。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">我这里以 Eclipse(pid 22296)为例,双击后直接展开,主界面展示了系统和jvm两大块内容,点击右下方jvm参数和系统属性可以参考详细的参数信息.</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.5892351274787535" data-type="jpeg" data-w="1059" src="/upload/ff2307bacc886ac73ff613262d21e304.jpg" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">因为VisualVM的插件太多,我这里主要介绍三个我主要使用几个:监控、线程、Visual GC</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">监控的主页其实也就是,cpu、内存、类、线程的图表</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.5385745775165319" data-type="jpeg" data-w="1361" src="/upload/6fe9294fb2ded296302c518a9f6771a5.jpg" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">线程和jconsole功能没有太大的区别</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.5385745775165319" data-type="jpeg" data-w="1361" src="/upload/6b573407884b2213665317b8deb2e2c0.jpg" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">Visual GC 是常常使用的一个功能,可以明显的看到年轻代、老年代的内存变化,以及gc频率、gc的时间等。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.5892351274787535" data-type="jpeg" data-w="1059" src="/upload/ff2307bacc886ac73ff613262d21e304.jpg" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">以上的功能其实jconsole几乎也有,VisualVM更全面更直观一些,另外VisualVM非常多的其它功能,可以分析dump的内存快照,</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">dump出来的线程快照并且进行分析等,还有其它很多的插件大家可以去探索</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.4447592067988669" data-type="jpeg" data-w="1059" src="/upload/a58d9d79223ab31088a0dc25d4d3b10e.jpg" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"> </figure> <h1 data-tool="mdnice编辑器" style="margin-top: 38px;margin-bottom: 10px;font-weight: bold;font-size: 24px;color: black;text-align: center;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/JdLkEI9sZffBdQ2u7mibDAK9aMrPQX92p4QGb38srSbibgab1mxM7o3JnPgzbBQG6VgaIt8z4AR4Z19ib0lKwUhBQ/640?wx_fmt=png&quot;);background-position: center top;background-repeat: no-repeat;background-size: 75px;line-height: 95px;"><span style="font-size: 20px;border-bottom: 2px solid rgb(46, 121, 80);color: rgb(0, 82, 255);">案例分析</span></h1> <h2 data-tool="mdnice编辑器" style="margin-top: 1em;margin-bottom: 10px;font-weight: bold;font-size: 22px;color: black;text-align: center;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/JdLkEI9sZffBdQ2u7mibDAK9aMrPQX92p9PkzXaOVe2vpPoibT7c5So9qmCTZMzysWcUrJAb6EIkicYicOppBhu6cA/640?wx_fmt=png&quot;);background-position: center center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 50px;"><span style="margin-top: 38px;margin-bottom: 10px;display: inline-block;height: 38px;line-height: 42px;background-position: left center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 63px;font-size: 18px;color: rgb(0, 82, 255);">准备模拟内存泄漏样例</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">1、定义静态变量HashMap</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">2、分段循环创建对象,并加入HashMap</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">代码如下:</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="margin-bottom: -7px;display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/JdLkEI9sZffBdQ2u7mibDAK9aMrPQX92pia02sQicAdU7r4icX4N0cF37m9r4Bmpxj6OFpPhShOgr4avmx7vU4FWvg/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 677px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;overflow-x: auto;color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(39, 40, 34);border-radius: 5px;"><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">import</span>&nbsp;java.util.HashMap;<br><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">import</span>&nbsp;java.util.Map;<br><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">class</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">CyclicDependencies</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(117, 113, 94);line-height: 26px;">//声明缓存对象</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">private</span>&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">static</span>&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">final</span>&nbsp;Map&nbsp;map&nbsp;=&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;HashMap();<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">static</span>&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">void</span>&nbsp;<span style="color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">main</span><span style="line-height: 26px;">(String&nbsp;args[])</span></span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">try</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(<span style="line-height: 26px;">10000</span>);<span style="color: rgb(117, 113, 94);line-height: 26px;">//给打开visualvm时间</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">catch</span>&nbsp;(InterruptedException&nbsp;e)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(117, 113, 94);line-height: 26px;">//循环添加对象到缓存</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">for</span>(<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">int</span>&nbsp;i=<span style="line-height: 26px;">0</span>;&nbsp;i&lt;<span style="line-height: 26px;">1000000</span>;i++){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TestMemory&nbsp;t&nbsp;=&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;TestMemory();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map.put(<span style="color: rgb(166, 226, 46);line-height: 26px;">"key"</span>+i,t);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: rgb(166, 226, 46);line-height: 26px;">"first"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(117, 113, 94);line-height: 26px;">//为dump出堆提供时间</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">try</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(<span style="line-height: 26px;">10000</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">catch</span>&nbsp;(InterruptedException&nbsp;e)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">for</span>(<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">int</span>&nbsp;i=<span style="line-height: 26px;">0</span>;&nbsp;i&lt;<span style="line-height: 26px;">1000000</span>;i++){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TestMemory&nbsp;t&nbsp;=&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;TestMemory();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map.put(<span style="color: rgb(166, 226, 46);line-height: 26px;">"key"</span>+i,t);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: rgb(166, 226, 46);line-height: 26px;">"second"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">try</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(<span style="line-height: 26px;">10000</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">catch</span>&nbsp;(InterruptedException&nbsp;e)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">for</span>(<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">int</span>&nbsp;i=<span style="line-height: 26px;">0</span>;&nbsp;i&lt;<span style="line-height: 26px;">3000000</span>;i++){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TestMemory&nbsp;t&nbsp;=&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;TestMemory();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map.put(<span style="color: rgb(166, 226, 46);line-height: 26px;">"key"</span>+i,t);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: rgb(166, 226, 46);line-height: 26px;">"third"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">try</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(<span style="line-height: 26px;">10000</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">catch</span>&nbsp;(InterruptedException&nbsp;e)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">for</span>(<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">int</span>&nbsp;i=<span style="line-height: 26px;">0</span>;&nbsp;i&lt;<span style="line-height: 26px;">4000000</span>;i++){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TestMemory&nbsp;t&nbsp;=&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;TestMemory();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map.put(<span style="color: rgb(166, 226, 46);line-height: 26px;">"key"</span>+i,t);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: rgb(166, 226, 46);line-height: 26px;">"forth"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">try</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(Integer.MAX_VALUE);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">catch</span>&nbsp;(InterruptedException&nbsp;e)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: rgb(166, 226, 46);line-height: 26px;">"qqqq"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">3、配置jvm参数如下:</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="margin-bottom: -7px;display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/JdLkEI9sZffBdQ2u7mibDAK9aMrPQX92pia02sQicAdU7r4icX4N0cF37m9r4Bmpxj6OFpPhShOgr4avmx7vU4FWvg/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 677px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;overflow-x: auto;color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(39, 40, 34);border-radius: 5px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-Xms512m<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-Xmx512m<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-XX:-UseGCOverheadLimit<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-XX:MaxPermSize=<span style="line-height: 26px;">50</span>m<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">4、运行程序并打卡visualvm监控</p> <h2 data-tool="mdnice编辑器" style="margin-top: 1em;margin-bottom: 10px;font-weight: bold;font-size: 22px;color: black;text-align: center;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/JdLkEI9sZffBdQ2u7mibDAK9aMrPQX92p9PkzXaOVe2vpPoibT7c5So9qmCTZMzysWcUrJAb6EIkicYicOppBhu6cA/640?wx_fmt=png&quot;);background-position: center center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 50px;"><span style="margin-top: 38px;margin-bottom: 10px;display: inline-block;height: 38px;line-height: 42px;background-position: left center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 63px;font-size: 18px;color: rgb(0, 82, 255);">使用JVisualVM分析内存泄漏</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">1、查看Visual GC标签,内容如下,这是输出first的截图</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;"><img data-ratio="0.5624438454627134" data-type="png" data-w="1113" src="/upload/ab98871d47c36a73d84abb8ddb0b485e.png" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"></p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">这是输出forth的截图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.5390070921985816" data-type="png" data-w="1128" src="/upload/c758bfad235ca33be80dd6c7e5ad3e14.png" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">通过2张图对比发现:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.07526881720430108" data-type="png" data-w="372" src="/upload/db7b5c4ad37616283738647313305ff1.png" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;height: 28px !important;width: 372px !important;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.05291005291005291" data-type="png" data-w="378" src="/upload/e0859ef2666c4628019ed6da4d6d1ba5.png" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 378px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">老生代一直在gc,当程序继续运行可以发现老生代gc还在继续:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.0515695067264574" data-type="png" data-w="446" src="/upload/95766a30ad78694e24667d3b20899fd1.png" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 446px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">增加到了7次,但是老生代的内存并没有减少。说明存在无法被回收的对象,可能是内存泄漏了。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">如何分析是那个对象泄漏了呢?打开抽样器标签:点击后如下图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.5024590163934426" data-type="png" data-w="1220" src="/upload/c33f8fe6648523f8c353d1b637e7e370.png" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">按照程序输出进行堆dump,当输出second时,dump一次,当输出forth时dump一次。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">进入最后dump出来的堆标签,点击类:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.13213213213213212" data-type="png" data-w="333" src="/upload/91c7eeb300179a0644e664c1fb050f45.png" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;background-color: rgb(238, 237, 235);border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);background-size: 22px;background-position: center center;background-repeat: no-repeat;display: block;border-radius: 4px;box-sizing: border-box !important;height: 45.7357px !important;width: 333px !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">点击右上角:“与另一个堆存储对比”。如图选择第一次导出的dump内容比较:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.8526315789473684" data-type="png" data-w="380" src="/upload/219887c060c421204220c26b457a4e95.png" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 380px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">比较结果如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.19369369369369369" data-type="png" data-w="666" src="/upload/b54038027b13cc8d7904e529fef25df5.png" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 666px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">可以看出在两次间隔时间内TestMemory对象实例一直在增加并且多了,说明该对象引用的方法可能存在内存泄漏。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">如何查看对象引用关系呢?</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">右键选择类TestMemory,选择“在实例视图中显示”,如下所示:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.4444444444444444" data-type="png" data-w="1125" src="/upload/703191d58cc0164fd1b7f2398640c747.png" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">左侧是创建的实例总数,右侧上部为该实例的结构,下面为引用说明,从图中可以看出在类CyclicDependencies里面被引用了,并且被HashMap引用。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">如此可以确定泄漏的位置,进而根据实际情况进行分析解决。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 1em;margin-bottom: 10px;font-weight: bold;font-size: 22px;color: black;text-align: center;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/JdLkEI9sZffBdQ2u7mibDAK9aMrPQX92p9PkzXaOVe2vpPoibT7c5So9qmCTZMzysWcUrJAb6EIkicYicOppBhu6cA/640?wx_fmt=png&quot;);background-position: center center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 50px;"><span style="margin-top: 38px;margin-bottom: 10px;display: inline-block;height: 38px;line-height: 42px;background-position: left center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 63px;font-size: 18px;color: rgb(0, 82, 255);">JVisualVM 远程监控 Tomcat</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">1、修改远程tomcat的catalina.sh配置文件,在其中增加:</p> <ol data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">JAVA_OPTS="$JAVA_OPTS</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">-Djava.rmi.server.hostname=192.168.122.128</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">-Dcom.sun.management.jmxremote.port=18999</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">-Dcom.sun.management.jmxremote.ssl=false</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">-Dcom.sun.management.jmxremote.authenticate=false"</p> <p style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">这次配置先不走权限校验。只是打开jmx端口。</p> <p style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">2、打开jvisualvm,右键远程,选择添加远程主机:</p> </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;"><img data-ratio="0.42328042328042326" data-type="png" data-w="378" src="/upload/3f0761d6de2438940db47bcf1c1fc0f2.png" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 378px !important;visibility: visible !important;"></p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">3、输入主机的名称,直接写ip,如下:</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;"><img data-ratio="0.18181818181818182" data-type="png" data-w="220" src="/upload/bf0d84fa9e5d1c2716b0639510b0f61b.png" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 220px !important;visibility: visible !important;"></p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">右键新建的主机,选择添加JMX连接,输入在tomcat中配置的端口即可。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">4、双击打开。完毕!</p> <h1 data-tool="mdnice编辑器" style="margin-top: 38px;margin-bottom: 10px;font-weight: bold;font-size: 24px;color: black;text-align: center;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/JdLkEI9sZffBdQ2u7mibDAK9aMrPQX92p4QGb38srSbibgab1mxM7o3JnPgzbBQG6VgaIt8z4AR4Z19ib0lKwUhBQ/640?wx_fmt=png&quot;);background-position: center top;background-repeat: no-repeat;background-size: 75px;line-height: 95px;"><span style="font-size: 20px;border-bottom: 2px solid rgb(46, 121, 80);color: rgb(0, 82, 255);">参考资料</span></h1> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">https://blog.csdn.net/kl28978113/article/details/53817827</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;color: rgb(74, 74, 74);line-height: 1.75em;">https://www.cnblogs.com/ityouknow/p/6437037.html</p> </section> <p><br></p> <section style="font-size: 16px;"> <section style="text-align: center;margin: 30px 0% 10px;" powered-by="xiumi.us"> <section style="display: inline-block;width: 95%;vertical-align: top;box-shadow: rgb(185, 185, 185) 1.41421px 1.41421px 6px;padding: 5px;"> <section style="margin: -20px 0% 5px;" powered-by="xiumi.us"> <section style="vertical-align: middle;display: inline-block;line-height: 0;box-shadow: rgb(0, 0, 0) 0px 0px 0px;"> <img data-ratio="0.0604167" src="/upload/eac62155141991460e1922655dcc3ae6.png" data-type="png" data-w="480" style="vertical-align: middle;box-sizing: border-box;"> </section> </section> <section style="margin: 10px 0%;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: middle;width: 38%;box-shadow: rgb(0, 0, 0) 0px 0px 0px;padding-left: 10px;"> <section style="margin-right: 0%;margin-left: 0%;" powered-by="xiumi.us"> <section style="vertical-align: middle;display: inline-block;line-height: 0;box-shadow: rgb(0, 0, 0) 0px 0px 0px;border-style: solid;border-width: 2px;border-radius: 0px;border-color: transparent;padding: 0px 0.5em;"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzU3NTY3MTQzMg==&amp;mid=2247485220&amp;idx=2&amp;sn=08e3d10a011ebaa3cb073f76533ab4ee&amp;scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="top: auto;left: auto;margin: 0px;right: auto;bottom: auto;"><img data-ratio="0.93361" src="/upload/1b39b5243dd08a3f02968589f3a58bf7.jpg" data-type="jpeg" data-w="241" style=" vertical-align: middle;box-sizing: border-box;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;margin: 0px; "></span></a> </section> </section> </section> <section style="display: inline-block;vertical-align: middle;width: 61.8%;"> <section style="font-size: 14px;" powered-by="xiumi.us"> <p><span style="font-size: 16px;">加入搜狐技术作者天团</span></p> <p><span style="font-size: 16px;">千元稿费等你来!</span></p> <p><span style="font-size: 16px;">戳这里!👈</span></p> <p><br></p> </section> </section> </section> </section> </section> </section> <p><br></p> <p><img class="rich_pages js_insertlocalimg" data-ratio="0.496875" data-s="300,640" src="/upload/dd71cb3db3e9867051184f316150576f.png" data-type="gif" data-w="640" style="white-space: normal;text-align: center;box-shadow: rgb(170, 170, 170) 0px 0px 14px 0px;"></p>

Flink 与 TiDB 构建高效易用的实时数仓

作者:微信小助手

<p style="letter-spacing: 0.544px;white-space: normal;font-size: 16px;background-color: rgb(255, 255, 255);color: rgb(0, 0, 0);font-family: PingFangSC-Light;text-align: center;" data-mpa-powered-by="yiban.io"><span style="font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;font-size: 12px;color: rgb(120, 114, 119);user-select: text !important;">点击上方 "</span><span style="font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;font-size: 12px;user-select: text !important;"><strong style="color: rgb(62, 62, 62);font-size: 14px;user-select: text !important;"><span style="letter-spacing: 0.544px;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(61, 170, 214);user-select: text !important;">zhisheng</span></strong></span><span style="font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;font-size: 12px;color: rgb(120, 114, 119);user-select: text !important;">"关注,&nbsp;<span style="letter-spacing: 0.544px;user-select: text !important;">星标或置顶一起成长</span></span><br></p> <p style="font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;color: rgb(43, 43, 43);font-size: 16px;background-color: rgb(255, 255, 255);text-align: center;"><a target="_blank" href="https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&amp;album_id=1337172142412169216&amp;__biz=MzIxMTE0ODU5NQ==#wechat_redirect" textvalue="Flink 从入门到精通" tab="innerlink" data-linktype="2" style="color: rgb(120, 172, 254);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;letter-spacing: 0.544px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 13px;line-height: 1.75em;user-select: text !important;"><span style="letter-spacing: 0.544px;line-height: 1.75em;user-select: text !important;">Flink 从入门到精通</span></a><span style="letter-spacing: 0.544px;color: rgb(136, 136, 136);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 13px;line-height: 1.75em;user-select: text !important;">&nbsp;系列文章</span></p> <p style="font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;color: rgb(43, 43, 43);font-size: 16px;background-color: rgb(255, 255, 255);text-align: center;"><span style="letter-spacing: 0.544px;color: rgb(136, 136, 136);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 13px;line-height: 1.75em;user-select: text !important;"><br></span></p> <section style="text-align: left;line-height: 1.75em;"> <span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 0.5px;">随着互联网飞速发展,企业业务种类会越来越多,业务数据量会越来越大,当发展到一定规模时,传统的数据存储结构逐渐无法满足企业需求,实时数据仓库就变成了一个必要的基础服务。以维表 Join 为例,数据在业务数据源中以范式表的形式存储,在分析时需要做大量的 Join 操作,降低性能。如果在数据清洗导入过程中就能流式的完成 Join,那么分析时就无需再次 Join,从而提升查询性能。</span> <br> </section> <section style="text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 0.5px;">&nbsp;</span> </section> <section style="text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 0.5px;">利用实时数仓,企业可以实现实时 OLAP 分析、实时数据看板、实时业务监控、实时数据接口服务等用途。但想到实时数仓,很多人的第一印象就是架构复杂,难以操作与维护。而得益于新版 Flink 对 SQL 的支持,以及 TiDB HTAP 的特性,我们探索了一个高效、易用的 Flink+TiDB 实时数仓解决方案。</span> </section> <section style="text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 0.5px;">&nbsp;</span> </section> <section style="text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 0.5px;">本文将首先介绍实时数仓的概念,然后介绍 Flink+TiDB 实时数仓的架构与优势,接着给出一些已经在使用中的用户场景,最后给出在 docker-compose 环境下的 Demo,用于读者进行尝试。</span> </section> <section style="text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 0.5px;"><br></span> </section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="margin: 20px 0% 10px;text-align: center;box-sizing: border-box;" powered-by="xiumi.us"> <section style="padding: 3px;display: inline-block;border-bottom: 5px solid rgb(71, 193, 168);color: rgb(40, 40, 38);font-size: 18px;box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong style="box-sizing: border-box;">实时数仓的概念</strong></p> </section> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br></p> </section> </section> <section style="text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 0.5px;">数据仓库的概念在 90 年代由 Bill Inmon 提出,是指一个面向主题的、集成的、相对稳定的、反映历史变化的集合,用于支持管理决策。当时的数据仓库通过消息队列收集来自数据源的数据,通过每天或每周进行一次计算以供报表使用,也称为离线数仓。</span> </section> <section style="text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 0.5px;"><br></span> </section> <p><br></p> <p style="text-align: center;"><img class="rich_pages" data-backh="193" data-backw="578" data-ratio="0.3338870431893688" data-s="300,640" data-type="png" data-w="602" src="/upload/d7c74c00c080965b197e084d9af980bb.png" style="width: 100%;height: auto;"></p> <p><br></p> <section style="text-align: center;line-height: 1.75em;"> <span style="co

TCP接入层的负载均衡、高可用、扩展性架构

作者:微信小助手

<section style="margin-top: 5px;text-align: justify;line-height: 1.75em;" data-mpa-powered-by="yiban.io"> <span style="font-size: 15px;letter-spacing: 1px;">今天和大家系统性聊聊TCP的负载均衡,高可用,与扩展性架构。</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <strong style="font-size: 15px;letter-spacing: 1px;"><br></strong> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <strong style="font-size: 15px;letter-spacing: 1px;">web-server的负载均衡,高可用,扩展性架构是怎么实施的?</strong> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <img data-ratio="0.4267352185089974" data-s="300,640" src="/upload/500c3c7aa3bdcf741833ed660c922d48.png" data-type="png" data-w="389"> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">互联网架构中,<span style="font-size: 15px;color: rgb(255, 104, 39);">web-server接入一般使用nginx来做反向代理</span>,实施负载均衡。整个架构分三层:</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>(1)上游调用层</strong>,一般是browser或者APP;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>(2)中间反向代理层</strong>,nginx;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>(3)下游真实接入集群</strong>,web-server,常见web-server的有tomcat,apache;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">那整个访问过程是怎么样的?</span></strong> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)browser向daojia.com发起请求;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)DNS将daojia.com解析为<span style="font-size: 15px;color: rgb(255, 104, 39);">外网IP</span>(1.2.3.4);</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(3)browser通过外网IP(1.2.3.4)访问nginx;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(4)nginx实施负载均衡策略,常见策略有轮询,随机,IP-hash等;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(5)nginx将请求转发给<span style="font-size: 15px;color: rgb(255, 104, 39);">内网IP</span>(192.168.0.1)的web-server;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">由于<span style="font-size: 15px;color: rgb(255, 104, 39);">http短连接,以及web应用无状态</span>的特性,理论上<strong>任何一个http请求落在任意一台web-server都应该得到正常处理</strong>。</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="color: rgb(0, 128, 255);"><em><span style="font-size: 15px;letter-spacing: 1px;">画外音:如果必须落在一台,说明架构可能不合理,难以水平扩展。</span></em></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">问题来了,<span style="font-size: 15px;color: rgb(255, 104, 39);">tcp是有状态的连接</span>,客户端和服务端一旦建立连接,<strong>一个client发起的请求必须落在同一台tcp-server上</strong>,此时如何做负载均衡,如何保证水平扩展呢?</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>方案一:单机法tcp-server</strong></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <img data-ratio="0.3333333333333333" data-s="300,640" src="/upload/e83c84d1a1371bad40ae24426baea0ee.png" data-type="png" data-w="255"> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">单个tcp-server显然是可以保证请求一致性:</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)client向tcp.daojia.com发起tcp请求;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)DNS将</span> <span style="letter-spacing: 1px;font-size: 12px;">tcp.daojia.com</span> <span style="font-size: 15px;letter-spacing: 1px;">解析为外网IP(1.2.3.4);</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(3)client通过外网IP(1.2.3.4)向tcp-server发起请求;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>这个方案有什么缺点?</strong></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 104, 39);font-size: 15px;letter-spacing: 1px;">无法保证高可用。</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>方案二:集群法tcp-server</strong></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <img data-ratio="0.3095823095823096" data-s="300,640" src="/upload/dd559d2e8c275f6aee7e112df56b302e.png" data-type="png" data-w="407"> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><span style="font-size: 15px;color: rgb(255, 104, 39);">可以通过搭建tcp-server集群来保证高可用</span>,<strong>客户端来实现负载均衡</strong>:</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)client内配置有tcp1/tcp2/tcp3.daojia.com三个tcp-server的外网IP;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)客户端通过“随机”的方式选择tcp-server,假设选择到的是tcp1.daojia.com;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(3)通过DNS解析tcp1.daojia.com;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(4)通过外网IP连接真实的tcp-server;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>如何保证高可用呢?</strong></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 104, 39);font-size: 15px;letter-spacing: 1px;">如果client发现某个tcp-server连接不上,则选择另一个。</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong><strong style="font-size: 15px;letter-spacing: 1px;white-space: normal;">这个方案有什么缺点?</strong></strong></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">每次连接前,需要多实施一次DNS访问:</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 104, 39);font-size: 15px;letter-spacing: 1px;">(1)难以预防DNS劫持;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)多一次DNS访问意味着<span style="font-size: 15px;color: rgb(255, 104, 39);">更长的连接时间</span>,这个不足在手机端更为明显;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>如何解决DNS的问题?</strong></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">直接将IP配置在客户端,可以解决上述两个问题,很多公司也就是这么做的,</span> <span style="color: rgb(0, 0, 0);font-size: 15px;letter-spacing: 1px;">俗称“</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">IP直通车</span> <span style="color: rgb(0, 0, 0);font-size: 15px;letter-spacing: 1px;">”。</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>“IP直通车”有什么新问题?</strong></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">将IP写死在客户端,在客户端实施负载均衡,<span style="font-size: 15px;color: rgb(255, 104, 39);">扩展性很差</span>:</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><span style="font-size: 15px;color: rgb(255, 104, 39);">(1)如果原有IP发生变化</span>,客户端得不到实时通知;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><span style="font-size: 15px;color: rgb(255, 104, 39);">(2)如果新增IP</span>,即tcp-sever扩容,客户端也得不到实时通知;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><span style="font-size: 15px;color: rgb(255, 104, 39);">(3)如果负载均衡策略变化</span>,需要升级客户端;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>方案三:服务端实施负载均衡</strong></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><span style="font-size: 15px;color: rgb(255, 104, 39);">只有将复杂的策略下沉到服务端,才能根本上解决扩展性的问题</span>。</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <img data-ratio="0.2403846153846154" data-s="300,640" src="/upload/570a11853500112fc94f434eacc617c9.png" data-type="png" data-w="520"> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><span style="font-size: 15px;color: rgb(255, 104, 39);">增加一个http接口,将客户端的“IP配置”与“均衡策略”放到服务端</span>是一个不错的方案:</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)client每次访问tcp-server前,先调用一个<strong>新增的get-tcp-ip接口</strong>,对于client而言,<span style="font-size: 15px;color: rgb(255, 104, 39);">这个http接口只返回一个tcp-server的IP;</span></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)这个http接口,实现的是原client的IP均衡策略;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(3)拿到tcp-server的IP后,和原来一样向tcp-server发起TCP长连接;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">这样的话,扩展性问题就解决了:</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)如果原有IP发生变化,只需要修改get-tcp-ip接口的配置;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)如果新增IP,也是修改get-tcp-ip接口的配置;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(3)如果负载均衡策略变化,不需要升级客户端;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">然而,<strong>新的问题</strong>又产生了,如果所有IP放在客户端,当有一个IP挂掉的时候,client可以再换一个IP连接,保证可用性,而get-tcp-ip接口只是维护静态的tcp-server集群IP,对于这些<span style="font-size: 15px;color: rgb(255, 104, 39);">IP对应的tcp-server是否可用</span>,是完全不知情的,怎么办呢?</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>方案四:tcp-server状态上报</strong></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <img data-ratio="0.5238095238095238" data-s="300,640" src="/upload/4977a70ab1ea86e310a31c9cd072768e.png" data-type="png" data-w="357"> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">get-tcp-ip接口怎么知道tcp-server集群中各台服务器是否可用呢,<span style="font-size: 15px;color: rgb(255, 104, 39);">tcp-server主动上报是一个潜在方案</span>,如果某一个tcp-server挂了,则会终止上报,对于停止上报状态的tcp-server,get-tcp-ip接口,将不返回给client相应的tcp-server的外网IP。</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>该设计的存在的问题?</strong></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">诚然,状态上报解决了tcp-server高可用的问题,但这个设计犯了一个<span style="font-size: 15px;color: rgb(255, 104, 39);">“反向依赖”的耦合小错误</span>:使得tcp-server要依赖于一个与本身业务无关的web-server。</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>方案五:tcp-server状态拉取</strong></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <img data-ratio="0.5363128491620112" data-s="300,640" src="/upload/39d218f6772ac0754ec3923ec170535a.png" data-type="png" data-w="358"> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>更优的方案</strong>是:<span style="font-size: 15px;color: rgb(255, 104, 39);">web-server通过“拉”的方式获取各个tcp-server的状态</span>,而不是tcp-server通过“推”的方式上报自己的状态。</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">这样的话,<span style="font-size: 15px;color: rgb(255, 104, 39);">每个tcp-server都独立与解耦</span>,只需专注于资深的tcp业务功能即可。</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <br> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>高可用、负载均衡、扩展性</strong>等任务<span style="font-size: 15px;color: rgb(255, 104, 39);">由get-tcp-ip的web-server专注来执行</span>。</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">多说一句,<span style="font-size: 15px;color: rgb(255, 104, 39);">将负载均衡实现在服务端</span>,还有一个<strong>好处</strong>,可以实现<span style="font-size: 15px;color: rgb(255, 104, 39);">异构tcp-server的负载均衡</span>,以及<span style="font-size: 15px;color: rgb(255, 104, 39);">过载保护</span>:</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>(1)静态实施</strong>:web-server下的多个tcp-server的IP可以配置负载权重,根据tcp-server的机器配置分配负载(nginx也有类似的功能);</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>(2)动态实施</strong>:web-server可以根据“拉”回来的tcp-server的状态,动态分配负载,并在tcp-server性能急剧下降时实施过载保护;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>总结</strong></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>web-server如何实施负载均衡?</strong></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 104, 39);font-size: 15px;letter-spacing: 1px;">利用nginx反向代理来轮询、随机、ip-hash。</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>tcp-server怎么快速保证请求一致性?</strong></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 104, 39);font-size: 15px;letter-spacing: 1px;">单机。</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>如何保证高可用?</strong></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 104, 39);font-size: 15px;letter-spacing: 1px;">客户配置多个tcp-server的域名。</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>如何防止DNS劫持,以及加速?</strong></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 104, 39);font-size: 15px;letter-spacing: 1px;">IP直通车,客户端配置多个tcp-server的IP。</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>如何保证扩展性?</strong></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><span style="font-size: 15px;color: rgb(255, 104, 39);">服务端提供get-tcp-ip接口</span>,向client屏屏蔽负载均衡策略,并实施便捷扩容。</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><strong>如何保证高可用?</strong></span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><span style="font-size: 15px;color: rgb(255, 104, 39);">tcp-server“推”</span>状态给get-tcp-ip接口,</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">or</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;"><span style="font-size: 15px;color: rgb(255, 104, 39);">get-tcp-ip接口“拉”</span>tcp-server状态。</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <br> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(0, 0, 0);">细节重要,<strong>思路比细节更重要</strong>。</span> </section> <section style="margin-top: 5px;text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(0, 0, 0);">系统性了解架构,希望大家有收获,<strong>谢转</strong>。</span> </section>

如何获取变量token的值

作者:测试人生路

一.什么是token 1.客户端使用用户名跟密码请求登录 2.服务端收到请求,去验证用户名与密码 3.验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端 4.客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 LocalStorage 里,客户端每次向服务端请求资源的时候需要带着服务端签发的Token 5.服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据 6web/APP登录的时候发送加密的用户名和密码到服务器,服务器验证用户名和密码,如果成功,以某种方式比如随机生成32位的字符串作为token,存储到服务器中,并返回 token到web/APP,以后web/APP请求时凡是需要验证的地方都要带上该 token,然后服务器端验证 token,成功返回所需要的结果,失败返回错误信息,让他重新登录。其中服务器上 token 设置一个有效期,每次web/APP请求的时候都验证token 和有效期。 二、如何获取token的值,进行接口测试 接口测试的工具大部分都可以获取登录之后返回的token值,这里给大家讲解如何用apipost获取token值的方法。 先打开apipost,进行登录接口的编写,然后获取token的值。 ![1.png](/storage/thumbnails/_signature/2BUTQ4G98FH6DNG945GQDA05A7.png) 接着我们来引用这个token的值,引用token的值需要我们先设置环境变量 ![2.png](/storage/thumbnails/_signature/27V8OU12CSL71FSNHRTTFMD8NA.png) ![3.png](/storage/thumbnails/_signature/52DOSC2BSQ4OQMG2PVA1832GB.png) 环境选择为新建好的环境,在引用url地址。引用格式为{{变量名}} ![4.png](/storage/thumbnails/_signature/2HNKNDKQRKFVDP7J0L2OGKMSCA.png) 在去设置后执行脚本获取token值,“token”是参数名称,response.json.token的意思是返回的json数据中的token值。 ![5.png](/storage/thumbnails/_signature/2MR02H1RHR3M69MGCLL5N73G4.png) 这些都设置好之后,就可以引用token了,token引用的方法和环境变量设置的url引用方法一样也是 ![6.png](/storage/thumbnails/_signature/7SDKVJP0Q3FVS2NC3NEU82QTM.png) 三、接口流程测试 token值引用好之后,就可以进行接口流程化测试了。 ![7.png](/storage/thumbnails/_signature/2PRLEEHQK9HLJQ13HK727EEDTF.png) 选择接口点击添加到流程测试中 ![8.png](/storage/thumbnails/_signature/7FCJO1RPBB53CH1R03OM8VT7R.png) ![9.png](/storage/thumbnails/_signature/39J6RG9EIP919KOIMG048IBH86.png) 进行流程测试 ![10.png](/storage/thumbnails/_signature/17ABTFOVM0UU9BBUU89RJQ0P7T.png) ![11.png](/storage/thumbnails/_signature/1N9LL7FF0NOG370EOMGEK00O7O.png) 这就是如何获取token值进行接口流程测试的步骤了。 工具下载地址:[https://www.apipost.cn/?dt=20201029](https://www.apipost.cn/?dt=20201029)

浅谈滴滴千万级派单算法

作者:微信小助手

<section class="xmteditor" style="display:none;" data-tools="新媒体管家" data-label="powered by xmt.cn"></section> <section style="text-align: center;margin-left: 8px;margin-right: 8px;" data-mpa-powered-by="yiban.io"> <img class="rich_pages" data-cropselx1="0" data-cropselx2="558" data-cropsely1="0" data-cropsely2="237" data-ratio="0.6" data-s="300,640" src="/upload/1f667b8862c167303be7cee78007b452.jpg" data-type="jpeg" data-w="800" style="float: left;width: 558px;height: 335px;"> </section> <p style="text-align: center;"><span style="color: rgb(120, 172, 254);font-size: 14px;"><strong>作者:</strong><strong style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 0.544px;white-space: pre-wrap;">王犇,</strong><span style="color: rgb(120, 172, 254);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: pre-wrap;">滴滴首席算法工程师</span></span><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: pre-wrap;color: rgb(120, 172, 254);font-size: 14px;"></span></p> <p style="text-align: center;"><span style="color: rgb(120, 172, 254);font-size: 14px;"><strong>来自:</strong><strong>滴滴技术</strong></span><span style="color: rgb(120, 172, 254);"><strong><span style="color: rgb(120, 172, 254);font-size: 15px;"></span></strong></span><br></p> <section style="font-size: 16px;"> <section style="margin: 10px 8px;"> <section style="display: inline-block;width: 100%;border-width: 1px;border-style: solid;border-color: transparent;padding: 10px;background-color: rgb(239, 239, 239);border-radius: 0px;"> <section style="transform: rotate(0deg);" powered-by="xiumi.us"> <section style="line-height: 1.75;font-size: 13px;"> <p>桔妹导读:说到滴滴的派单算法,大家可能感觉到既神秘又好奇,从出租车扬召到司机在滴滴平台抢单最后到平台派单,大家今天的出行体验已经发生了翻天覆地的变化,面对着每天数千万的呼叫,滴滴的派单算法一直在持续努力让更多人打到车,本篇文章会着重介绍我们是如何分析和建模这个问题,并且这其中面临了怎样的算法挑战,以及介绍一些我们常用的派单算法,这些算法能够让我们不断的提升用户的打车确定性。</p> </section> </section> </section> </section> </section> <p><br></p> <p><br></p> <h4 style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 32px;"><em><strong><span style="color: rgb(255, 125, 65);">1.</span></strong></em></span></h4> <h3 cid="n70" mdtype="heading" class="" style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 18px;"><strong><span style="color: rgb(64, 64, 64);">为什么我们需要更好的派单算法</span></strong><strong><span style="color: rgb(64, 64, 64);"></span></strong></span><span style="font-size: 14px;"></span></h3> <pre class="" ng-bind-html="message.MMActualContent" style="letter-spacing: 0.544px;background-color: rgb(255, 255, 255);"><p style="margin-left: 8px;margin-right: 8px;"><img class="rich_pages" data-copyright="0" data-ratio="0.0734375" data-s="300,640" src="/upload/8c0b0343939ede75396663634e9b61ae.png" data-type="png" data-w="1280" style="visibility: visible !important;width: 677px !important;"></p></pre> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">说到滴滴的派单算法,大家可能感觉到既神秘又好奇,从扬召到抢单到派单,我们又是如何演进到今天大家的打车体验的呢,我们首先来看一看,好的派单算法为什么是出行行业不可或缺的能力?</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">回想几年前,当我们还没有滴滴的时候,只能在寒风或者酷暑中等待可能有、可能没有的扬招出租车,到后来可以从滴滴上呼叫一辆出租车,乘客可以在室内相对舒适的等待车辆的到达,从线上到线下,乘客的确定性得到第一次的提升,然而这还不够,抢单的模式注定我们的应答率天花板不会太高,在15年,滴滴上线快车业务,我们从抢单演进到了派单模式,乘客的应答率有了20个点以上的提升,很多时候能够全天能够高达90+(高峰&amp;局部供需紧张应答率会相对吃紧),乘客确定性再一次得到大幅的提升,由此可见,派单模式为滴滴创造了巨大用户价值。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">再看近年来不断兴起的O2O业务,从国内外的网约车公司,包括我们的友商Uber、Lyft都基于派单的产品形态进行司机和乘客之间的交易撮合,Uber上市的时候把派单引擎也作为核心技术能力放在了招股书中;再看我们的国内的外卖平台,核心派单系统的优劣也决定了整个平台的交易效率(单均配送成本)和用户体验(配送时长);最后,整个大物流行业近年来也不断在进行线上化的改造,如何撮合货物和司机,以及更好的拼单能力也是整个交易环节的关键和商业模式是否成立的前提。从运人到运物,派单引擎目前越来越多的被应用在现实的商业和生活中。</span></p> <p style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);"><br></p> <p style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);"><br></p> <h4 style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 32px;"><em><strong><span style="color: rgb(255, 125, 65);">2.</span></strong></em></span></h4> <h2 style="white-space: normal;line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><strong><span style="color: rgb(64, 64, 64);font-size: 18px;">派单问题初探</span></strong><span style="font-size: 14px;color: rgb(64, 64, 64);"></span></h2> <pre class="" ng-bind-html="message.MMActualContent" style="letter-spacing: 0.544px;background-color: rgb(255, 255, 255);"><p style="margin-left: 8px;margin-right: 8px;"><img class="rich_pages" data-copyright="0" data-ratio="0.0734375" data-s="300,640" src="/upload/8c0b0343939ede75396663634e9b61ae.png" data-type="png" data-w="1280" style="visibility: visible !important;width: 677px !important;"></p></pre> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">言归正传,这里我们也来看一下,滴滴网约车平台到底是怎么派单的。首先,我们来看下我们面对的是什么样的问题?</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">&nbsp;</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><em><strong><span style="font-size: 14px;color: rgb(64, 64, 64);">“订单分配&nbsp;即是在派单系统中将 乘客发出的订单 分配给 在线司机 的过程”</span></strong></em><span style="font-size: 14px;color: rgb(64, 64, 64);"></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">&nbsp;</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">这是一个看似简单的,但实际上非常复杂的问题。说到这,可能有很多人就会问,能否就把 我的订单分配给离我最近的司机就好了?</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">的确啊,实际上目前滴滴的派单算法最大的原则就是 “就近分配” (70%~80%的订单就是分配给了最近的司机),据我所知,目前世界上其他的竞品公司(包括Uber),也均是基于这个原则分单的。&nbsp;</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">我们进一步来看这个问题,如果我们只按照就近分配,先到先得的贪心策略,是不是能最好的满足平台所有乘客和司机的诉求呢?答案是否定的,原因就在于,如果我们只基于当前时刻和当前局部的订单来进行决策,忽视了未来新的订单&amp;司机的变化,还忽视了和你相邻的其他区域甚至整个城市的需求(注:在时序上来看,新的司机&amp;订单的出现会导致,贪心策略反而违背了就近分配的目标)。这就是为什么这个问题依然是非常复杂的原因。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">这里稍微有点抽象了,不过没关系,我们再来一步一步的拆解一下订单分配的问题,让大家有个更好的理解:</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">简单看,在我们的平台上,每一个时刻,都有N个订单在被乘客创建,同时有M个司机可以被我们用来进行分配,我们强大的平台能够为派单算法给出司机的实时的地理位置坐标,以及所有订单的起终点位置,并且告诉我们每一个司机接到订单的实时导航距离。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">&nbsp;</span></p> <h3 data-anchor-id="7yqg" style="margin-right: 8px;margin-left: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;"><strong><span style="color: rgb(64, 64, 64);">▍</span>如果是1个订单、1个司机</strong></h3> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <section style="text-align: center;margin-left: 8px;margin-right: 8px;"> <img class="rich_pages" data-ratio="0.5625" data-s="300,640" src="/upload/d3c5c0ad8f8b53145dae6945b061907.png" data-type="png" data-w="720" style=""> </section> <p style="line-height: 1.75em;text-align: center;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">&nbsp; &nbsp; &nbsp;&nbsp;</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">看上去似乎就非常简单了,我们直接把这个订单指派给这个司机就好了嘛。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">“那么为什么有时候附近有辆空车却不能指派给你呢?”</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">实际线上的系统会比这里稍微复杂一点,原因一方面有可能是司机正好网络出现故障,或者正在和客服沟通等等导致司机无法听单,另一方面的原因是并不是所有的车都能够符合服务你订单的要求,最基本的策略其实是人工设定的规则过滤。举几个最基础的例子:</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <ul style="list-style-type: disc;margin-left: 8px;margin-right: 8px;" class=" list-paddingleft-2"> <li> <section style="line-height: 1.75em;"> <span style="font-size: 14px;color: rgb(64, 64, 64);">规则A:快车司机不能接专车订单</span> </section></li> <li> <section style="line-height: 1.75em;"> <span style="font-size: 14px;color: rgb(64, 64, 64);">规则B:保证司机接单后不会通过限行限号区域</span> </section></li> <li> <section style="line-height: 1.75em;"> <span style="font-size: 14px;color: rgb(64, 64, 64);">规则C:为设定实时目的地的司机过滤不顺路区域</span> </section></li> <li> <section style="line-height: 1.75em;"> <span style="font-size: 14px;color: rgb(64, 64, 64);">规则D:为只听预约单司机过滤实时订单</span> </section></li> <li> <section style="line-height: 1.75em;"> <span style="font-size: 14px;color: rgb(64, 64, 64);">规则E:同一个订单只会发给一个司机一次</span> </section></li> <li> <section style="line-height: 1.75em;"> <span style="color: rgb(64, 64, 64);font-size: 14px;">......</span> </section></li> </ul> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">&nbsp;&nbsp;&nbsp;&nbsp;</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">必须澄清的一点是这里的规则并不会造成分单时不公平的效果,而完全是为了业务能正常运行而设立的,这些策略承担着保证业务正确性的重要职责。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">&nbsp;</span></p> <h3 data-anchor-id="7yqg" style="margin-right: 8px;margin-left: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;"><strong><span style="color: rgb(64, 64, 64);">▍</span>如果是1个订单和2个司机</strong></h3> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">假设这两个司机都能够分配给这个订单,那么我们来看系统应该是如何分配的。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">首先第一种情况是,同一时刻下,这两个司机和订单的距离都完全一样的情况下,系统应该如何分配?</span></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <br> </section> <section style="text-align: center;margin-left: 8px;margin-right: 8px;"> <img class="rich_pages" data-ratio="0.5625" data-s="300,640" src="/upload/b732be64346cbbf7f8127333b154727f.png" data-type="png" data-w="720" style=""> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <br> </section> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">刚才也说到,我们平台订单分配最大的原则是就近分配,当距离完全一样的情况下,当前我们系统上会主要考虑司机的服务分的优劣,服务分较高的司机会获取到这个订单(注:服务分对分单的影响,简单的理解可以换算为多少分可以换成多少米距离的优势,这块不是今天的重点就不展开介绍),再说明一下,系统用到的是地图的导航距离,而非人直观看到的直线距离,有时候差一个路口就会因为需要掉头导致距离差异很大;并且如果司机的定位出现问题,也会出现分单过远的情况。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">那么我们来看第二种情况,如果A司机离的近,B司机离的远,系统怎么派?</span></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <br> </section> <section style="text-align: center;margin-left: 8px;margin-right: 8px;"> <img class="rich_pages" data-ratio="0.5625" data-s="300,640" src="/upload/564e87d84eca964bddc8814a4ca28455.png" data-type="png" data-w="720" style=""> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <br> </section> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">这就简单了,根据就近分配的原则,我们会把A司机分配给这个订单。嘿嘿~~,假设我们再把问题设置的更加实际一点,当订单发出时,B司机已经在线并空闲,但是A司机还没有出现(没有上线,或者还在送乘客),但再过1s,离得更近的A司机突然出现可被分单了,假设我们使用先到先得的贪心策略,那么B司机就会被分给这个订单,那就违背我们希望就近分单的目标了:(。所以看上去简单,但实际情况下,算法还需要变的更好一些,这个问题我们把它叫做派单中的时序问题,我们后面再来看怎么解决。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><strong><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></strong></p> <h3 data-anchor-id="7yqg" style="margin-right: 8px;margin-left: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;"><strong><span style="color: rgb(64, 64, 64);">▍</span>如果有N个乘客、M个司机</strong></h3> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">最后我们来考虑最复杂的多对多的情况,这也是线上系统每天高峰期都需要面对的挑战,我们一般把这种情况会形式化为一个二部图的匹配问题,在运筹领域也叫做matching的问题,如图所示:</span></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <br> </section> <section style="text-align: center;margin-left: 8px;margin-right: 8px;"> <img class="rich_pages" data-ratio="0.5625" data-s="300,640" src="/upload/272c58d495ad272f2d9759589e695d9c.png" data-type="png" data-w="720" style=""> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <br> </section> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">我们再把这个问题具象一点,假设这个时候我们有20个乘客,有20个司机,这些乘客都可以被这20个司机中的一个接驾,我们的系统需要把这20个乘客都分配出去,并且让大家的总体接驾的时长最短。听上去是不是有点复杂?我们套用下组合数学的知识,这其中可能的解法存在20的阶乘那么多,20的阶乘是什么概念呢?20*19*18*…*1= 2432902008176640000,这个数巨大无比,想要完全的暴力搜索是绝对不可能的。这里需要更聪明的办法。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">&nbsp;</span></p> <h3 data-anchor-id="7yqg" style="margin-right: 8px;margin-left: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;"><strong><span style="color: rgb(64, 64, 64);">▍</span>如果有N个乘客、M个司机,一会再来几个乘客和司机?</strong></h3> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">这就是派单问题最大的挑战,我们不仅仅需要当前这个时刻的最优,我们要考虑未来一段时间整体的最优,新来的司机和乘客会在整个分配的网络中实时插入新的节点,如何更好的进行分配也就发生了新的变化,所以如何考虑时序对我们非常重要,这个问题在业内也被称为Dynamic VRP问题,这个Dynamic也就是随时间时序变化的意思,这也就是为什么,滴滴的派单问题远复杂于物流行业的相对静态的货物和路线的规划问题。假设我们知道了未来供需的完全真实的变化,仿真告诉我们,我们的系统有可能可以利用同样的运力完成1.2~1.5倍的需求量,这也是派单算法的同学持续为之努力的方向。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">想起前段时间的吐槽大会,大家提到文嵩曾说我们的派单问题比alpha go还要难,其实这两个问题还确实有点相似,都是在超大的搜索空间中找到一个近似最优的解,而alpha go则会在一个更加明确的游戏规则和环境中进行求解,它的难点在于博弈,而我们的派单问题难点在于未来供需不确定性&amp;用户行为的不确定性。近年来在学界,已经有不少尝试在利用类似alpha go的技术进行VRP&amp;TSP等方向的探索,强化学习结合运筹理论是未来运筹界非常前沿的方向之一(非技术同学可以跳过此处:))</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);"><br></p> <h4 style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 32px;"><em><strong><span style="color: rgb(255, 125, 65);">3.</span></strong></em></span></h4> <h2 style="white-space: normal;line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><strong><span style="color: rgb(64, 64, 64);font-size: 18px;">派单算法简介</span></strong><span style="font-size: 14px;color: rgb(64, 64, 64);"></span></h2> <pre class="" ng-bind-html="message.MMActualContent" style="letter-spacing: 0.544px;background-color: rgb(255, 255, 255);"><p style="margin-left: 8px;margin-right: 8px;"><img class="rich_pages" data-copyright="0" data-ratio="0.0734375" data-s="300,640" src="/upload/8c0b0343939ede75396663634e9b61ae.png" data-type="png" data-w="1280" style="visibility: visible !important;width: 677px !important;"></p><p style="margin-left: 8px;margin-right: 8px;"><span style="letter-spacing: 0.544px;color: rgb(64, 64, 64);font-size: 14px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">上面我们已经描述了什么是订单分配问题,并且它所面临的各种挑战,</span><span style="color: rgb(64, 64, 64);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 14px;letter-spacing: 0.544px;">那么在这里我们来</span></p><p style="margin-left: 8px;margin-right: 8px;"><span style="color: rgb(64, 64, 64);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 14px;letter-spacing: 0.544px;">聊一聊我们线上的派单策略是如何解决其中一部分问题的。</span></p></pre> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">在介绍具体策略之前,首先我们来说一下派单算法大的原则,目前派单策略主要的原则是:站在全局视角,尽量去满足尽可能多的出行需求,保证乘客的每一个叫车需求都可以更快更确定的被满足,并同时尽力去提升每一个司机的接单效率,让总的接驾距离和时间最短。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">如何理解这个原则呢?我们说策略会站在全局的角度去达成全局最优,这样对于每一个独立的需求来看,派单可能就不是“局部最优&nbsp;&nbsp;&nbsp;”,不过可以告诉大家的是,就算在这个策略下,仍然有70%~80%的需求也是符合当前距离最近的贪心派单结果的。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">接下来,这里会拿两个重要的派单策略的来进行介绍。(这里的内容主要是讲清楚策略的motivation为主哈,细节不再展开)</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <h3 data-anchor-id="7yqg" style="margin-right: 8px;margin-left: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;"><strong><span style="color: rgb(64, 64, 64);">▍</span>批量匹配(全局最优)</strong></h3> <p style="margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">派单策略中最为基础的部分,就是为了解决上一节所提到的时序问题。这个算法几乎是所有类似派单系统为了解决这个问题的最基础模型,在Uber叫做Batching Matching,我们内部也叫做“全局最优” 或者 “延迟集中分单”。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">这个Idea其实也非常直观,由于用户订单的产生和司机的出现往往并不在同一时间点,在时间维度上贪婪的分单方式(即每个订单出现时即选择附近最近的司机派单)并不能获得全局最优的效果。一个自然的想法就是先让乘客和司机稍等一会,待收集了一段时间的订单和司机信息后,再集中分配。这样,有了相对较多、较密集的订单、司机后,派单策略即可找到更近更合理的派单方式了。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">找寻司机和订单分配的全局最优是一个&nbsp;二分图匹配问题&nbsp;(bipartite graph matching)&nbsp;,一边是乘客、一边是司机,可用运筹优化中各种解决Matching问题的方法进行求解。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">和再大家澄清一下,我们所采用的批量匹配的模式和大家所希望的,“把离我最近的司机派给我”的「就近派单模式」并不矛盾,我们也是寻求“乘客接驾时长最短”的最优解,大多数情况下也是指派离你最近的司机,但充分满足每一个乘客的“把离我最近的司机派给我”的个体需求, 有些时候反而会导致部分乘客的需求无法得到满足,比如说下面这种情况:</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">当编号1和2两个乘客同时叫车, 如果完全按照“就近派单”的模式, 虽然可以让1号乘客先被接单, 但是2号乘客会因为接驾距离较远, 导致等待时间变长, 甚至因为最近的司机超出平台派单距离, 导致2号乘客叫不到车。1、2号乘客总等待时长15分钟, 平均等待时长7.5分钟。</span></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <br> </section> <section style="text-align: center;margin-left: 8px;margin-right: 8px;"> <img class="rich_pages" data-ratio="0.5625" data-s="300,640" src="/upload/2f16a7f939623f37a2b1d534a0e7cbed.png" data-type="png" data-w="720" style=""> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <br> </section> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">我们采取的做法是, 把距离较远的2号车派给1号乘客。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">把1号车派给2号乘客, 这样一来, 1号乘客和2号乘客, 平均等待时长缩短为5分钟, 比就近派单,缩短了2.5分钟, 总等待时长缩短为10分钟, 比就近派单, 缩短了足足5分钟。</span></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <br> </section> <section style="text-align: center;margin-left: 8px;margin-right: 8px;"> <img class="rich_pages" data-ratio="0.5625" data-s="300,640" src="/upload/c81ce4b627f88c17c91d1db66292751c.png" data-type="png" data-w="720" style=""> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <br> </section> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">通过提升全局的效率,才能转化为让更多乘客的需求得到满足。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">&nbsp;</span></p> <h3 data-anchor-id="7yqg" style="margin-right: 8px;margin-left: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;"><strong><span style="color: rgb(64, 64, 64);">▍</span>基于供需预测的分单</strong></h3> <p style="margin-left: 8px;margin-right: 8px;"><span style="color: rgb(64, 64, 64);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 14px;"><br></span></p> <p style="margin-left: 8px;margin-right: 8px;"><span style="color: rgb(64, 64, 64);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 14px;">“如果有先知告诉我们未来每一个订单的生成时间&amp;地点,每一个司机的上线时间&amp;地点,派单就会变成非常轻松的一件事”</span><br></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="color: rgb(64, 64, 64);font-size: 14px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="color: rgb(64, 64, 64);font-size: 14px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">刚才所说的批量匹配的方法,理论上能够保证那一个批次的匹配是最优的。但是这样就够了吗?</span><br></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">很遗憾,以上所述的延迟集中分单的策略只能解决部分的问题,仍不是一个完全的方案。其最大的问题,在于用户对系统派单的&nbsp;响应时间&nbsp;容忍度有限,很多情况下短短的几秒钟即会使用户对平台丧失信心,从而取消订单。故实际线上我们只累积了几秒钟的订单和司机信息进行集中分单,而这在大局上来说仍可近似看做时间维度上的贪婪策略。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">若想即时的获得最优派单结果,唯一的方法是利用对未来的预测,即进行基于供需预测的分单。这种想法说来玄妙,其实核心内容也很简单:如果我们预测出未来一个区域更有可能有更多的订单/司机,那么匹配的时候就让这个区域的司机/订单更多去等待匹配这同一个区域的订单/司机。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <h3 data-anchor-id="7yqg" style="margin-right: 8px;margin-left: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;"><span style="font-size: 16px;"><strong><span style="color: rgb(64, 64, 64);">▍</span>连环派单</strong></span></h3> <p style="margin-left: 8px;margin-right: 8px;"><span style="color: rgb(64, 64, 64);font-size: 14px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"><br></span></p> <p style="margin-left: 8px;margin-right: 8px;"><span style="color: rgb(64, 64, 64);font-size: 14px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">基于供需预测的分单有很大意义,但由于预测的不确定性,其实际效果很难得到保证。为此,我们使用了一种更有确定性的预测方式来进行派单,即&nbsp;连环派单。</span><br></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><em><strong><span style="font-size: 14px;color: rgb(64, 64, 64);">“连环派单,即将订单指派给&nbsp;即将结束服务&nbsp;的司机,条件为如果司机的终点与订单位置很相近”</span></strong></em><span style="font-size: 14px;color: rgb(64, 64, 64);"></span></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <br> </section> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5625" data-s="300,640" src="/upload/bf5dd2357a2b6f9e83c42eb7dfa833cd.png" data-type="png" data-w="720" style=""></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <br> </section> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">与预测订单的分布相反,连环派单预测的是下一时刻空闲司机的所在位置。由于高峰期空闲司机多为司机完成订单后转换而来,预测司机的位置就变成了一个相对确定性的问题,即监测司机到目的地的距离和时间。当服务中的司机距终点很近,且终点离乘客新产生的订单也很近时,便会命中连环派单逻辑。司机在结束上一单服务后,会立刻进入新订单的接单过程中,有效地压缩了订单的应答时间、以及司机的接单距离。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <h3 data-anchor-id="7yqg" style="margin-right: 8px;margin-left: 8px;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;"><span style="font-size: 16px;"><strong><span style="color: rgb(64, 64, 64);">▍</span>如何做的更好</strong></span></h3> <p style="margin-left: 8px;margin-right: 8px;"><span style="color: rgb(64, 64, 64);font-size: 14px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"><br></span></p> <p style="margin-left: 8px;margin-right: 8px;"><span style="color: rgb(64, 64, 64);font-size: 14px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">整个派单算法核心克服的是未来供需的不确定性,动态的时空结构的建模,以及用户行为的不确定性,对于这些不确定性我们现在更多采用深度学习方法对我们的时空数据&amp;用户行为进行建模预测。</span><br></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="color: rgb(64, 64, 64);font-size: 14px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="color: rgb(64, 64, 64);font-size: 14px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">另外,我们的问题相对于传统推荐搜索领域,多了一层匹配决策,我们到底积攒多久的订单进行分配,对于每一个分配来说我们都面临着分或者不分,现在分还是未来分配,并且分给谁的问题,这个问题天生就可以建模为强化学习问题,目前在我们的系统中也引入了强化学习方法来优化更长期的收益。</span><br></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">除了不断去优化之前说到的派单问题,整个派单系统还面临着大量其他的挑战,包括如何利用快车优享等多个品类的运力进行跨层的最优分配,如何同时对用户&amp;司机&amp;平台短期长期等多个目标进行优化,如何同时优化预约&amp;实时订单,如何在具备网络效应的场景下对算法进行评估,如果建立一个较为精准的仿真系统等等,这里既是挑战,也是AI For Transportation中大量新的重新定义问题和创新算法的机会。</span></p> <p style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);"><br></p> <p style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);"><br></p> <h4 style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 32px;"><em><strong><span style="color: rgb(255, 125, 65);">4.</span></strong></em></span></h4> <p style="white-space: normal;line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><strong><span style="font-size: 18px;"><span style="color: rgb(64, 64, 64);">&nbsp;</span><span style="color: rgb(64, 64, 64);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">总结</span></span></strong></p> <pre class="" ng-bind-html="message.MMActualContent" style="letter-spacing: 0.544px;background-color: rgb(255, 255, 255);"><p style="margin-left: 8px;margin-right: 8px;"><img class="rich_pages" data-copyright="0" data-ratio="0.0734375" data-s="300,640" src="/upload/8c0b0343939ede75396663634e9b61ae.png" data-type="png" data-w="1280" style="visibility: visible !important;width: 677px !important;"></p></pre> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">每天, 我们的派单系统要面对超过3000万用户的叫车需求, &nbsp;&nbsp;高峰期每分钟接收超过6万乘车需求,平均每两秒就需要匹配几百到上千的乘客和司机 。我们当前的派单策略相对于最初的派单策略版本,每天能够多满足百万以上乘客的出行需求。为了让更多人能更快、更确定的打到车,我们的交易策略团队将在更好的公平感知的前提下,不断地优化和打磨我们的派单算法,为乘客&amp;司机创造更多价值。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);">当然当前的派单策略还有很多不够完善和完备的地方,本身也是一个相当复杂的问题和系统,一方面借此机会让大家对派单有更好的理解和认识,另一方面,也更欢迎大家对我们提出更多的宝贵意见,帮助我们进一步成长。</span></p> <p style="line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 14px;color: rgb(64, 64, 64);"><br></span></p> <p><br></p> <section class="" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <p class="" style="max-width: 100%;min-height: 1em;color: rgb(62, 62, 62);font-size: 16px;letter-spacing: 0.544px;text-align: center;box-sizing: border-box !important;word-wrap: break-word !important;">长按订阅更多精彩▼</p> <p style="max-width: 100%;min-height: 1em;color: rgb(62, 62, 62);font-size: 16px;letter-spacing: 0.544px;text-align: center;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="rich_pages" data-ratio="1" data-s="300,640" src="/upload/cff6d4b6b063076da067005708088611.jpg" data-type="jpeg" data-w="258" style="box-shadow: rgb(170, 170, 170) 0px 0px 14px 0px;box-sizing: border-box !important;word-wrap: break-word !important;visibility: visible !important;width: 205px !important;"></p> <p style="max-width: 100%;min-height: 1em;color: rgb(62, 62, 62);font-size: 16px;letter-spacing: 0.544px;text-align: right;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;word-wrap: break-word !important;">如有收获,点个在看,诚挚感谢</span><img class="" data-ratio="1" src="/upload/5f7454d24a334e968c32b8ce9ae53c5.png" data-type="png" data-w="19" style="display: inline-block;vertical-align: text-bottom;box-sizing: border-box !important;word-wrap: break-word !important;visibility: visible !important;width: 19px !important;"></p> </section>

接口工具使用分析(apipost、jmeter、postman、swagger等)

作者:测试人生路

一、接口都有哪些类型? 接口一般分为两种:1.程序内部的接口 2.系统对外的接口 系统对外的接口:比如你要从别的网站或服务器上获取资源或信息,别人肯定不会把 数据库共享给你,他只能给你提供一个他们写好的方法来获取数据,你引用他提供的接口就能使用他写好的方法,从而达到数据共享的目的。 程序内部的接口:方法与方法之间,模块与模块之间的交互,程序内部抛出的接口,比如bbs系统,有登录模块、发帖模块等等,那你要发帖就必须先登录,那么这两个模块就得有交互,它就会抛出一个接口,供内部系统进行调用。 接口的分类:1.webservice接口 2.http api接口 webService接口是走soap协议通过http传输,请求报文和返回报文都是xml格式的,我们在测试的时候都用通过工具才能进行调用,测试。 http api接口是走http协议,通过路径来区分调用的方法,请求报文都是key-value形式的,返回报文一般都是json串,有get和post等方法,这也是最常用的两种请求方式。 json是一种通用的数据类型,所有的语言都认识它。(json的本质是字符串,他与其他语言无关,只是可以经过稍稍加工可以转换成其他语言的数据类型,比如可以转换成 Python中的字典,key-value的形式,可以转换成JavaScript中的原生对象,可以转换成 java中的类对象等。) 二、接口–前端、后端和测试 前端对接口进行使用:通过后端人员给的接口文档,来进行Ajax的设计,通过接口向服务发送请求,获取响应的数据,然后通过返回的数据进行下一步的页面跳转和显示。 后端生成接口:通过编写接口,为前端提供与服务器和数据请求交互的通道。编写对应的接口,需要传递的参数,参数类型等等。然后生成接口文档,分享给前端,让其按照接口文档编写对应的Ajax。 测试验证接口:可以通过接口文档,进行接口验证,查看后端开发的接口和前端所写的Ajax是否对应,有没有出错的接口,还可通过接口流程测试,知道整个系统之间的接口是否是相对应的,有没有接口是不对的,或者没有正常运行。 三、前端、后端和测试使用的接口工具 前端:一般使用postman、apipost或者jmeter进行接口验证和查看响应值 后端:多用swagger、apipost、postman等接口文档生成工具和测试工具 测试:jmeter、apipost和postman等可以对接口进行验证测试。 四、jmeter、postman、apipost、swagger工具介绍 jmeter可以进行接口测试和性能测试,但是对于做单纯的接口测试jmeter操作起来没有postman、apipost使用起来方便。jmeter重点在于压力测试,稳定性测试和负载测试。针对于接口和程序的稳定性设计的一块以软件性能为主接口测试为辅的接口测试工具。 ![1.png](/storage/thumbnails/_signature/3HP1OAJITPS5G4KMM2OGG2NGH1.png) postman是Google开发的一款接口测试的插件,也有客户端。国内禁用Google之后,postman的插件就不好下载和使用了。postman这款接口测试工具,是一款很轻便的接口验证工具,可以通过输入请求方法、url、参数直接进行接口请求访问,验证接口是否开通,还可以查看返回的响应值查看接口开发是否正常。不过因为是Google开发的所以只支持英文版。对于英文不好的人使用起来特别难受。 ![2.png](/storage/thumbnails/_signature/1E592CODF7TFJ2V3PONETJNQQN.png) apipost这款接口测试工具,主要针对于接口验证和接口文档生成。apipost这款接口测试工具,是一款很轻便的接口验证工具,可以通过输入请求方法、url、参数直接进行接口请求访问,验证接口是否开通,还可以查看返回的响应值查看接口开发是否正常。根据这些接口验证信息,直接可以生成在线文档和离线版的word文档。是一款很棒的接口测试和接口文档生成工具,又不像swagger生成的接口文档都是英文的阅读起来也不太方便。apipost还具备协同工作,可以很有效的实现前端的接口联调。 ![3.png](/storage/thumbnails/_signature/DDCHN754TVJOTSHD63S0UMG6I.png) swagger是一款通过针对与后端开发人员的一款接口文档生成工具。主要通过在代码中的注释生成接口文档的工具,不过生成的接口文档是英文的。 ![4.png](/storage/thumbnails/_signature/36IJSJ47DV0743AKJ6QK2APRJ6.png) 工具下载地址: jmeter:https://jmeter.apache.org/ apipost:[https://www.apipost.cn/?dt=20201030](https://www.apipost.cn/?dt=20201030) swagger:https://swagger.io/

使用抓包工具fiddler和apipost进行接口测试

作者:测试人生路

一、进行接口测试准备的东西 1.接口测试工具:apipost、jmeter等 2.接口文档,没有接口文档就用接口信息获取工具 3.接口信息收取工具:fiddler抓包工具、浏览器开发者工具(f12)等 二、web接口测试需要获取的东西 web接口测试需要知道的三个条件 1.请求方式:get、post、put、patch、delete等 2.url地址:分为http请求和https是请求,如:http://www.baidu.com和https://www.baidu.com 3.body传递的参数:一般是以json的格式传递参数如:"name":"xiaoming","pwd":"123"。一般以post传递参数请求为多。 ![1.png](/storage/thumbnails/_signature/71CHHG1M5KGBAN59BJI1PPIMI.png) 三、fiddler抓包工具 fiddler是由 C# 开发的最强大好用的免费web调试工具之一,可记录所有客户端和服务见的 http 以及 https 请求,可监视设断点,甚至修改输入输出数据,它还包含了一个强大的基于事件脚本的子系统,并且能使用 .net 语言来拓展。 fiddler就是通过我们对网页的操作使用而进行的接口信息的抓取的。抓取之后按照上面需求的请求方法、url和body来查找需要的数据。 ![2.png](/storage/thumbnails/_signature/2RDP2VU7CFSE2UPNH0VNMJ235P.png) 这是一个简单的登录请求被fiddler抓取到的信息,我们可以用到的分别是: 1.Protocol请求类型:http或https。这里是http 2.host+url两个加起来形成的接口访问地址。这里的请求地址为:127.0.0.1:8888/login 3.Request Haeders(请求头部信息)中的请求方法:get、post等。这里是post请求 ![3.png](/storage/thumbnails/_signature/1C0OLM8SCHU44RI6OANVR3RV9U.png) 之后再点击Inspectors中的WebForms查看body参数。 获取的参数为,参数名:参数值,name:xiaoming,pwd:111 ![4.png](/storage/thumbnails/_signature/6NS1JTFJHVRNUUB3NI5ER5NR2.png) 四、接口测试 通过fiddler已经收取到这个接口的具体信息之后,我们通过接口测试工具apipost进行接口测试。 选择请求方法post、请求地址:http://127.0.0.1:8888/login、body参数:name:xiaoming,pwd:111 ![5.png](/storage/thumbnails/_signature/1U989DG7570NEOLOOPSJ5ONHC7.png) 查看请求结果 ![6.png](/storage/thumbnails/_signature/2VEAS55F4P7IK6NH6EAOUF17A8.png) 这就是通过fiddler和apipost进行接口测试的步骤。 fiddler下载地址:https://www.telerik.com/fiddler apipost下载地址:[https://www.apipost.cn/?dt=20201031](https://www.apipost.cn/?dt=20201031)

接口测试人员需要掌握的知识技能

作者:测试人生路

## 一、首先明白接口是什么 软件接口是指程序中具体负责在不同模块之间传输或接受数据的并做处理的类或者函数。(而不是指传输的数据!!) ## 二、什么是接口测试 接口测试就是通过向接口传递数据来测试这个接口是否正确。比如:一个QQ登录功能接口,就需要我们传递QQ号和密码去验证这个登录接口是否正确,能否使用。 ## 三、进行接口测试需要掌握哪些知识 1、了解系统及内部各个组件之间的业务逻辑交互; 2、了解接口的I/O(input/output:输入输出); 3、了解协议的基本内容,包括:通信原理、三次握手、常用的协议类型、报文构成、数据传输方式、常见的状态码、URL构成等; 4、常用的接口测试工具,比如:apipost、jmeter、loadrunner、soapUI等; 5、数据库基础操作命令(检查数据入库、提取测试数据等); 6、常见的字符类型,比如:char、varchar、text、int、float、datatime、string等; ## 四、如何学这些技能? 1、系统间业务交互逻辑:通过需求文档、流程图、思维导图、沟通等很多渠道和方式; 2、协议:推荐《图解http》这本书,内容生动,相对算是入门级的书籍,其他的还有《图解tcp、IP》等; 3、接口测试工具:百度这些工具,然后你会发现,好多的教学博客、相关问题解决方案、以及一些基于工具的书籍,当然,选择合适的书很重要; 4、数据库操作命令:学习网站(W3C、菜鸟教程)、教学博客,以及一些数据库相关书籍,入门级推荐:《mysql必知必会》、《oracle PL/SQL必知必会》等 5、知乎,百度和csdn等各大技术论坛都是你学习的好帮手 ## 五、接口测试分为两大类 1.手工通过工具进行测试 一般使用的工具有apipost、jmeter、postman等,博主使用的是国产的接口测试工具apipsot。 ![1.png](/storage/thumbnails/_signature/1BP3HPK85Q2NRM0LDNHLVNNB9E.png) 手工测试方法:通过抓包或其他方法(比如看文档)准备好输入数据包,然后用发包的工具把数据发给服务端的接口,之后校验其返回值。 2.自动化接口测试 以上,大家已经了解了手工做接口测试的流程。 那么下一步就是把一些接口测试编写成脚本,放在本地(自己电脑上),人工触发去批量得执行这些测试,并自动校验返回结果。 这里推荐一下使用的工具。 如果你是零基础的,推荐你用apipost或jmeter,两者都不需要你具备任何代码功底就能用。 我一般使用的是apipost的流程测试功能,把写好的接口,选择进行点击开始,就可以进行接口自动化测试了。 ![2.png](/storage/thumbnails/_signature/3P7T864AVVI8N9AJKUBOIE2KC2.png) 假如你有编程基础,可以考虑使用python+requests+pytest/robotframework来做接口测试。如果用了python+requests,那么性能测试方面可以用python+locust。也可以不用locust,只要你掌握了前面提过的数据驱动的思想,配合一些自动化框架开发基础,也一样可以把接口测试做到能在其他性能测试工具里重用,当然这个就复杂了,以后再说吧。 接口测试工具apipost下载地址:[https://www.apipost.cn/?dt=20201101](https://www.apipost.cn/?dt=20201101)

刚来的大神彻底干掉了代码中的if else...

作者:微信小助手

<section style="display:none;" data-tools="新媒体管家" data-label="powered by xmt.cn" data-mpa-powered-by="yiban.io"> <br> </section> <p style="line-height: 1.75em;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"><span style="font-size: 14px;color: rgb(136, 136, 136);">作者丨漫话编程</span><br></p> <p style="line-height: 1.75em;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"><span style="font-size: 14px;color: rgb(136, 136, 136);">来源丨漫话编程(mhcoding)</span><br></p> <section style="line-height: 1.75em;padding-left: 0.5em;padding-right: 0.5em;"> <br> </section> <section style="line-height: 1.75em;padding-left: 0.5em;padding-right: 0.5em;"> <section style="line-height: 1.75em;"> <section style="font-size: 16px;box-sizing: border-box;"> <section powered-by="xiumi.us" style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="padding-top: 10px;padding-right: 10px;padding-left: 10px;box-sizing: border-box;background-color: rgb(239, 239, 239);letter-spacing: 1.5px;"> <span style="display: inline-block;width: 27.7031px;line-height: 0.8;font-weight: bolder;box-sizing: border-box;font-size: 16px;"> <section> “ </section></span> <section> <section style="padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"> <span style="font-size: 15px;color: rgb(136, 136, 136);">对于业务开发来说,业务逻辑的复杂是必然的。</span> <span style="font-size: 15px;color: rgb(136, 136, 136);">随着业务发展,需求只会越来越复杂,为了考虑到各种各样的情况,代码中不可避免的会出现很多 if-else。</span> <span style="letter-spacing: 1px;font-size: 16px;"></span> </section> </section> </section> <section style="clear: both;box-sizing: border-box;"> <br> </section> </section> </section> </section> </section> <section style="line-height: 1.75em;padding-left: 0.5em;padding-right: 0.5em;"> <br> </section> <section style="text-align: center;margin-left: 8px;margin-right: 8px;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"> <img class="rich_pages" data-ratio="0.6626936829558999" data-s="300,640" src="/upload/f0232a833aae9e02da5418543e32c25e.png" data-type="png" data-w="839" style=""> </section> <section style="text-align: center;line-height: 1.75em;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"> <span style="color: rgb(89, 89, 89);letter-spacing: 1px;font-size: 16px;"><em>图片来自&nbsp;Pexels</em></span> </section> <section style="line-height: normal;padding-left: 0.5em;padding-right: 0.5em;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"> <span style="color: rgb(89, 89, 89);letter-spacing: 1px;font-size: 16px;">一旦代码中 if-else 过多,就会大大的影响其可读性和可维护性。</span> </section> <figure style="padding-left: 0.5em;padding-right: 0.5em;"> <img data-ratio="0.7097222222222223" src="/upload/79d4626fd2cbc197a38bfbc6c2ce1f66.jpg" data-type="jpeg" data-w="720" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;" title=""> </figure> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-top: 5px;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"> <span style="color: rgb(89, 89, 89);letter-spacing: 1px;font-size: 16px;">首先可读性,不言而喻,过多的 if-else 代码和嵌套,会使阅读代码的人很难理解到底是什么意思。尤其是那些没有注释的代码。</span> </section> <p style="line-height: normal;padding-left: 0.5em;padding-right: 0.5em;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"> <span style="color: rgb(89, 89, 89);letter-spacing: 1px;font-size: 16px;">其次是可维护性,因为 if-else 特别多,想要新加一个分支的时候,就会很难添加,极其容易影响到其他的分支。</span> </section> <p style="line-height: normal;padding-left: 0.5em;padding-right: 0.5em;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"> <span style="color: rgb(89, 89, 89);letter-spacing: 1px;font-size: 16px;">笔者曾经看到过一个支付的核心应用,这个应用支持了很多业务的线上支付功能,但是每个业务都有很多定制的需求,所以很多核心的代码中都有一大坨 if-else。</span> </section> <p style="line-height: normal;padding-left: 0.5em;padding-right: 0.5em;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"> <span style="color: rgb(89, 89, 89);letter-spacing: 1px;font-size: 16px;">每个新业务需要定制的时候,都把自己的 if 放到整个方法的最前面,以保证自己的逻辑可以正常执行。这种做法,后果可想而知。</span> </section> <p style="line-height: normal;padding-left: 0.5em;padding-right: 0.5em;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"> <span style="color: rgb(89, 89, 89);letter-spacing: 1px;font-size: 16px;">其实,if-else 是有办法可以消除掉的,其中比较典型的并且使用广泛的就是借助策略模式和工厂模式,准确的说是利用这两个设计模式的思想,彻底消灭代码中的 if-else。</span> </section> <p style="line-height: normal;padding-left: 0.5em;padding-right: 0.5em;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"> <span style="color: rgb(89, 89, 89);letter-spacing: 1px;font-size: 16px;">本文就结合这两种设计模式,介绍如何消除 if-else,并且,还会介绍如何和 Spring 框架结合,这样读者看完本文之后就可以立即应用到自己的项目中。</span> </section> <p style="line-height: normal;padding-left: 0.5em;padding-right: 0.5em;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"> <span style="color: rgb(89, 89, 89);letter-spacing: 1px;font-size: 16px;">本文涉及到一些代码,但是作者尽量用通俗的例子和伪代码等形式使内容不那么枯燥。</span> </section> <section style="line-height: normal;padding-left: 0.5em;padding-right: 0.5em;"> <br> </section> <section mpa-from-tpl="t" style="padding-left: 0.5em;padding-right: 0.5em;"> <section mpa-from-tpl="t"> <section mpa-from-tpl="t"> <section style="box-sizing: border-box;font-size: 16px;"> <section style="border-bottom: 1px solid black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;letter-spacing: 1.5px;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><span style="font-size: 16px;">恶心的 if-else</span></p> </section> </section> </section> <p style="line-height: normal;"><br></p> </section> </section> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"> <span style="letter-spacing: 1px;color: rgb(71, 193, 168);font-size: 16px;">假设我们要做一个外卖平台,有这样的需求:</span> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;letter-spacing: 1.5px;"> <span style="color: rgb(89, 89, 89);letter-spacing: 1px;font-size: 16px;">外卖平台上的某家店铺为了促销,设置了多种会员优惠,其中包含超级会员折扣 8 折、普通会员折扣 9 折和普通用户没有折扣三种。</span> </section></li> <li> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;letter-spacing: 1.5px;"> <span style="color: rgb(89, 89, 89);letter-spacing: 1px;font-size: 16px;">希望用户在付款的时候,根据用户的会员等级,就可以知道用户符合哪种折扣策略,进而进行打折,计算出应付金额。</span> </section></li> <li> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;letter-spacing: 1.5px;"> <span style="color: rgb(89, 89, 89);letter-spacing: 1px;font-size: 16px;">随着业务发展,新的需求要求专属会员要在店铺下单金额大于 30&nbsp;元的时候才可以享受优惠。</span> </section></li> <li> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;letter-spacing: 1.5px;"> <span style="color: rgb(89, 89, 89);letter-spacing: 1px;font-size: 16px;">接着,又有一个变态的需求,如果用户的超级会员已经到期了,并且到期时间在一周内,那么就对用户的单笔订单按照超级会员进行折扣,并在收银台进行强提醒,引导用户再次开通会员,而且折扣只进行一次。</span> </section></li> </ul> <p style="line-height: normal;padding-left: 0.5em;padding-right: 0.5em;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"> <span style="letter-spacing: 1px;color: rgb(71, 193, 168);font-size: 16px;">那么,我们可以看到以下伪代码:</span> </section> <pre style="max-width: 100%;color: inherit;font-size: inherit;font-variant-ligatures: normal;orphans: 2;widows: 2;line-height: inherit;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;padding-left: 0.5em;padding-right: 0.5em;"> <section style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);letter-spacing: 1.5px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"> <span style="font-size: 16px;"><span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;BigDecimal&nbsp;calPrice(BigDecimal&nbsp;orderPrice,&nbsp;String&nbsp;buyerType)&nbsp;{</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;(用户是专属会员)&nbsp;{</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;(订单金额大于<span style="max-width: 100%;line-height: inherit;color: rgb(174, 135, 250);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">30</span>元)&nbsp;{</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;returen&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(174, 135, 250);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">7</span>折价格;</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;}</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;(用户是超级会员)&nbsp;{</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">return</span>&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(174, 135, 250);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">8</span>折价格;</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;}</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;(用户是普通会员)&nbsp;{</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">if</span>(该用户超级会员刚过期并且尚未使用过临时折扣){</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;临时折扣使用次数更新();</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;returen&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(174, 135, 250);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">8</span>折价格;</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">return</span>&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(174, 135, 250);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">9</span>折价格;</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;}</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">return</span>&nbsp;原价;</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">}</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> </section></pre> <section style="line-height: normal;padding-left: 0.5em;padding-right: 0.5em;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"> <span style="color: rgb(89, 89, 89);letter-spacing: 1px;font-size: 16px;">以上,就是对于这个需求的一段价格计算逻辑,使用伪代码都这么复杂,如果是真的写代码,那复杂度可想而知。</span> </section> <section style="line-height: normal;padding-left: 0.5em;padding-right: 0.5em;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"> <span style="color: rgb(89, 89, 89);letter-spacing: 1px;font-size: 16px;">这样的代码中,有很多 if-else,并且还有很多的 if-else 的嵌套,无论是可读性还是可维护性都非常低。</span> <span style="color: rgb(89, 89, 89);letter-spacing: 1px;line-height: 1.75em;font-size: 16px;">那么,如何改善呢?</span> </section> <section mpa-from-tpl="t" style="padding-left: 0.5em;padding-right: 0.5em;"> <section mpa-from-tpl="t"> <section mpa-from-tpl="t"> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="transform: rotate(0deg);-webkit-transform: rotate(0deg);-moz-transform: rotate(0deg);-o-transform: rotate(0deg);box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom: 1px solid black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;letter-spacing: 1.5px;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><span style="font-size: 16px;">策略模式</span></p> </section> </section> </section> </section> <section style="line-height: normal;"> <br> </section> </section> </section> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"> <span style="color: rgb(89, 89, 89);letter-spacing: 1px;font-size: 16px;">接下来,我们尝试引入策略模式来提升代码的可维护性和可读性。</span> </section> <section style="line-height: normal;padding-left: 0.5em;padding-right: 0.5em;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"> <span style="letter-spacing: 1px;color: rgb(71, 193, 168);font-size: 16px;">首先,定义一个接口:</span> </section> <pre style="max-width: 100%;color: inherit;font-size: inherit;font-variant-ligatures: normal;orphans: 2;widows: 2;line-height: inherit;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;padding-left: 0.5em;padding-right: 0.5em;"> <section style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);letter-spacing: 1.5px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"> <span style="max-width: 100%;line-height: inherit;color: rgb(128, 128, 128);font-size: 16px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">/**<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;">&nbsp;*&nbsp;@author&nbsp;mhcoding<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;">&nbsp;*/</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;"><span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">interface</span>&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(165, 218, 45);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">UserPayService</span>&nbsp;{</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(128, 128, 128);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">/**<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;计算应付价格<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span></span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="max-width: 100%;line-height: inherit;word-break: inherit !important;">public</span>&nbsp;BigDecimal&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(165, 218, 45);word-break: inherit !important;">quote</span>(<span style="max-width: 100%;line-height: inherit;color: rgb(255, 152, 35);word-break: inherit !important;">BigDecimal&nbsp;orderPrice</span>)</span>;</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">}</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> </section></pre> <section style="line-height: normal;padding-left: 0.5em;padding-right: 0.5em;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"> <span style="letter-spacing: 1px;color: rgb(71, 193, 168);font-size: 16px;">接着定义几个策略类:</span> </section> <pre style="max-width: 100%;color: inherit;font-size: inherit;font-variant-ligatures: normal;orphans: 2;widows: 2;line-height: inherit;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;padding-left: 0.5em;padding-right: 0.5em;"> <section style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);letter-spacing: 1.5px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"> <span style="max-width: 100%;line-height: inherit;color: rgb(128, 128, 128);font-size: 16px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">/**<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;">&nbsp;*&nbsp;<span style="max-width: 100%;color: inherit;line-height: inherit;word-break: inherit !important;">@author</span>&nbsp;mhcoding<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;">&nbsp;*/</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;"><span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="max-width: 100%;color: inherit;line-height: inherit;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);word-break: inherit !important;">class</span>&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(165, 218, 45);word-break: inherit !important;">ParticularlyVipPayService</span>&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);word-break: inherit !important;">implements</span>&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(165, 218, 45);word-break: inherit !important;">UserPayService</span>&nbsp;</span>{</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(91, 218, 237);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">@Override</span></span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="max-width: 100%;line-height: inherit;word-break: inherit !important;">public</span>&nbsp;BigDecimal&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(165, 218, 45);word-break: inherit !important;">quote</span><span style="max-width: 100%;line-height: inherit;color: rgb(255, 152, 35);word-break: inherit !important;">(BigDecimal&nbsp;orderPrice)</span>&nbsp;</span>{</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;(消费金额大于<span style="max-width: 100%;line-height: inherit;color: rgb(174, 135, 250);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">30</span>元)&nbsp;{</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">return</span>&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(174, 135, 250);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">7</span>折价格;</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;}</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">}</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;"><span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="max-width: 100%;color: inherit;line-height: inherit;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);word-break: inherit !important;">class</span>&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(165, 218, 45);word-break: inherit !important;">SuperVipPayService</span>&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);word-break: inherit !important;">implements</span>&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(165, 218, 45);word-break: inherit !important;">UserPayService</span>&nbsp;</span>{</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(91, 218, 237);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">@Override</span></span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="max-width: 100%;line-height: inherit;word-break: inherit !important;">public</span>&nbsp;BigDecimal&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(165, 218, 45);word-break: inherit !important;">quote</span><span style="max-width: 100%;line-height: inherit;color: rgb(255, 152, 35);word-break: inherit !important;">(BigDecimal&nbsp;orderPrice)</span>&nbsp;</span>{</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">return</span>&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(174, 135, 250);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">8</span>折价格;</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;}</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">}</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;"><span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="max-width: 100%;color: inherit;line-height: inherit;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);word-break: inherit !important;">class</span>&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(165, 218, 45);word-break: inherit !important;">VipPayService</span>&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);word-break: inherit !important;">implements</span>&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(165, 218, 45);word-break: inherit !important;">UserPayService</span>&nbsp;</span>{</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(91, 218, 237);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">@Override</span></span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="max-width: 100%;line-height: inherit;word-break: inherit !important;">public</span>&nbsp;BigDecimal&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(165, 218, 45);word-break: inherit !important;">quote</span><span style="max-width: 100%;line-height: inherit;color: rgb(255, 152, 35);word-break: inherit !important;">(BigDecimal&nbsp;orderPrice)</span>&nbsp;</span>{</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">if</span>(该用户超级会员刚过期并且尚未使用过临时折扣){</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;临时折扣使用次数更新();</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;returen&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(174, 135, 250);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">8</span>折价格;</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">return</span>&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(174, 135, 250);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">9</span>折价格;</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;}</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;">}</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> </section></pre> <section style="line-height: normal;padding-left: 0.5em;padding-right: 0.5em;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;padding-left: 0.5em;padding-right: 0.5em;letter-spacing: 1.5px;"> <span style="color: rgb(89, 89, 89);letter-spacing: 1px;font-size: 16px;">引入了策略之后,我们可以按照如下方式进行价格计算:</span> </section> <pre style="max-width: 100%;color: inherit;font-size: inherit;font-variant-ligatures: normal;orphans: 2;widows: 2;line-height: inherit;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;padding-left: 0.5em;padding-right: 0.5em;"> <section style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;line-height: 18px;font-size: 14px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);letter-spacing: 1.5px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"> <span style="max-width: 100%;line-height: inherit;color: rgb(128, 128, 128);font-size: 16px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">/**<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;">&nbsp;*&nbsp;@author&nbsp;mhcoding<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;">&nbsp;*/</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <span style="font-size: 16px;"><span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(248, 35, 117);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">class</span>&nbsp;<span style="max-width: 100%;line-height: inherit;color: rgb(165, 218, 45);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: inherit !important;word-break: inherit !important;">Test</span>&nbsp;{</span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;

java中的匿名内部类总结

作者:cdhqyj

匿名内部类也就是没有名字的内部类 正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写 但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口 实例1:不使用匿名内部类来实现抽象方法 abstract class Person { public abstract void eat(); } class Child extends Person { public void eat() { System.out.println("eat something"); } } public class Demo { public static void main(String[] args) { Person p = new Child(); p.eat(); } } 运行结果:eat something 可以看到,我们用Child继承了Person类,然后实现了Child的一个实例,将其向上转型为Person类的引用 但是,如果此处的Child类只使用一次,那么将其编写为独立的一个类岂不是很麻烦? 这个时候就引入了匿名内部类 实例2:匿名内部类的基本实现 abstract class Person { public abstract void eat(); } public class Demo { public static void main(String[] args) { Person p = new Person() { public void eat() { System.out.println("eat something"); } }; p.eat(); } } 运行结果:eat something 可以看到,我们直接将抽象类Person中的方法在大括号中实现了 这样便可以省略一个类的书写 并且,匿名内部类还能用于接口上 实例3:在接口上使用匿名内部类 interface Person { public void eat(); } public class Demo { public static void main(String[] args) { Person p = new Person() { public void eat() { System.out.println("eat something"); } }; p.eat(); } } 运行结果:eat something 由上面的例子可以看出,只要一个类是抽象的或是一个接口,那么其子类中的方法都可以使用匿名内部类来实现 常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是继承Runnable接口 实例4:Thread类的匿名内部类实现 public class Demo { public static void main(String[] args) { Thread t = new Thread() { public void run() { for (int i = 1; i <= 5; i++) { System.out.print(i + " "); } } }; t.start(); } } 运行结果:1 2 3 4 5 实例5:Runnable接口的匿名内部类实现 public class Demo { public static void main(String[] args) { Runnable r = new Runnable() { public void run() { for (int i = 1; i <= 5; i++) { System.out.print(i + " "); } } }; Thread t = new Thread(r); t.start(); } } 运行结果:1 2 3 4 5