<h1><p>
</p></h1><h2>问题背景</h2><h2><p> 最近在负责一个订单系统的业务研发,本来不是件困难的事。但是服务的启动时间很慢,慢的令人发指。单次启动的时间约在10多分钟左右,基本一次迭代、开发,大部分的时间都花在了启动项目上。忍无可忍的我,终于决定找到启动慢的原因。</p><p>
</p></h2><h2>方案探索</h2><h2><p> 起初对于优化项目启动速度,是毫无头绪。也是傻傻的从百度上去搜解决的方案。一下子就搜到了Jprofiler这个软件,据说是能快速找到错误栈的位置。但是不得不说这软件真的很坑,不仅收费(MAC破解巨难找,找到了还打不开),而且实际因为很多Spring类都是采用动态代理加载的,Jprofiler根本判断不出来错误位置在哪。</p><p> 尝试Jprofiler无果后,从网上还看到了一个另外的方法,可以通过对运行中的线程作快照,来定位是否存在有死循环的线程。进而优化启动速度。</p><div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/26056344-57ab893d302dfacc.jpeg" img-data="{"format":"jpeg","size":144024,"height":452,"width":1892}" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div><p> 采用Thread dump的方式,比较适合你清楚大致原因的时候使用,否则你盲目的去截取到的线程,实际上也很难定位是不是当前线程的问题。尽管错误栈很全,但意味着你需要了解的源码更深。对我这种小白,依旧很难get到具体的原因。</p><p>
</p></h2><h2>深入钻研</h2><h2><p> 采用网上的解决方案都无疾而终后,决定还是采用最笨的方法解决,就一点点的debug吧!于是在SpringBoot的启动类org.springframework.boot.SpringApplication#run上打满了debug点,逐个关键的debug点去调试。</p><div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/26056344-bf3cac2f2a9ec1b7.jpeg" img-data="{"format":"jpeg","size":76801,"height":545,"width":1024}" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div><p> 尽管方案很笨也很耗时,启动一次基本10分钟左右。但是很快定位到了启动缓慢的原因。在Springboot的BEAN后处理器的加载方法中,有一个关键的Bean容器DSLContext启动及其的慢,大概需要6、7分钟左右。org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization</p><div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/26056344-a17716cc25677357.jpeg" img-data="{"format":"jpeg","size":32224,"height":366,"width":1014}" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div><p>然而,dslContext是个啥玩意,他为啥又让我的系统启动慢了呢?带着疑惑又搜了一遍百度,直到看到了这篇文章。https://www.jianshu.com/p/f65653a0f11c 。</p><div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/26056344-418d3c9b0b2c2d26.jpeg" img-data="{"format":"jpeg","size":74911,"height":709,"width":923}" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div><p> 文章里写到,dslContext启动慢的原因主要是有个:AnnotationAwareAspectJAutoProxyCreator的处理器,该处理器会扫描dslContext中的方法,并逐一判断当前的方式是否需要动态代理。dslContext中包含约800+的方法启动自然会很慢。</p><p> </p></h2><h2>最终解决</h2><h2><p> 知道了原因,那么自然也就知道了解决方案。只要让Springboot不扫描到这个dslContext组件了,那么就可以加快启动速度了不是?那么自然就可以从两个角度出发:</p><p><strong>1、修改Springboot的扫描范围,不扫描即可;</strong></p><p><strong>2、不导入dslContext的依赖包,让Springboot扫描不到</strong></p><p> 我首先尝试了第一种方法,修改了启动类上<strong>@ComponentScan</strong>和<strong>@EnableFeignClients</strong>的两个注解的扫描范围,然而,无论我怎么修改,实际上都没有生效。(大概率猜测是因为dslContext并不是采用@Componet注解的方式而是采用@Configuration注入的方式导致。)</p><p> 无奈之下,只能按照第二种思路去考虑解决方案。然而,作为一个饱经风霜的项目,maven依赖多到数不清,根本不知道该从何下手。</p><p>尝试通过<strong>Maven Helper</strong>插件去搜索dslContext的maven依赖,却也是毫无作用。</p><p>(PS:这里不得不提一下Maven Helper这个插件,这个插件可以很快找到我们所依赖的maven,是我平日用来排除相关依赖的利器。)</p><div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/26056344-7b23e3cf3a078bbb.jpeg" img-data="{"format":"jpeg","size":59940,"height":655,"width":782}" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div><div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/26056344-67ab8287f915f793.jpeg" img-data="{"format":"jpeg","size":41569,"height":910,"width":819}" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div><p>也就是抱着尝试的心态,在百度下搜索了一下“<strong>使用dslContext</strong>”的关键字,很幸运的是,在第二个搜索位置跳出了<strong>jooq</strong>这个名词。</p><div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/26056344-94e21eda79ebc0a0.jpeg" img-data="{"format":"jpeg","size":31483,"height":233,"width":619}" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div><p>于是怀疑,是不是这个jooq依赖把dslContext导入进来了呢?尝试着一搜,果然!</p><div class="image-package"><img src="https://upload-images.jianshu.io/upload_images/26056344-8a9ff2a413dedcc2.jpeg" img-data="{"format":"jpeg","size":21654,"height":252,"width":1005}" class="uploaded-img" style="min-height:200px;min-width:200px;" width="auto" height="auto"/>
</div><p>毫不犹豫点击了exclude,再启动一次。问题解决!</p><p>
</p></h2><h2>经验总结</h2><h2><p>解决项目启动慢的原因其实是个很依靠个人经验和运气、玄学的过程,但是还是有一些方法有迹可循。</p><p>1、可以考虑<strong>Jprofiler去记录线程的启动时间</strong>。(但本次效果不佳,可能需要更正常的打开方式)</p><p>2、可以考虑采用<strong>截取线程快照</strong>的方式定位。</p><p>3、最最笨的方法就是<strong>采用Debug的方式</strong>定位。</p><p>在定位到具体的启动缓慢的原因后,如果是因为注入的问题,有下面两条解决思路:</p><p>1、不扫描对应的Component组件,可以通过<strong>修改@Component、@EnableFeignClients的basePackge参数</strong>来控制。</p><p>2、如果上述的参数没有生效,可以考虑尝试百度定<strong>位引入这个组件的maven依赖是什么,并借助Maven Helper插件将该依赖排除</strong>。</p>
</h2>
系统启动太慢,调优后我直呼Nice
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...