hi,你好!欢迎访问本站!登录
本站由网站地图腾讯云宝塔系统阿里云强势驱动
当前位置:首页 - 教程 - 杂谈 - 正文 君子好学,自强不息!

一个一般类就醒目趴你的springboot,你信吗?

2019-11-18杂谈搜奇网24°c
A+ A-

  先声明本人并非题目党,假如看了本篇文章而且以为没有获得任何收成,请您随意留言骂我,本人毫不还口,已对springboot管窥蠡测大大神,求放过!

  不BB了,直接上代码,请列位在本身的springboot项目随意一个包下复制进去以下类(不要修正什么东西),假如你的springboot还能站起来算我输!

@Component
public class Environment {
}

  运转springboot的启动类会报以下毛病,然后你删除这个类,你的springboot又能大步流星了,你能够就会疑心人生了,这代码有毒。先申明我的springboot是2.1.7.RELEASE,我也试了最新的2.2,报错基础一致!

2019-11-02 00:42:46.181  INFO 13568 --- [           main] com.rdpaas.platform.demo.RunApplication  : Starting RunApplication on DESKTOP-9KL4U5L with PID 13568 (E:\project2018\platform\demo\target\classes started by 49519 in E:\project2018\platform)
2019-11-02 00:42:46.183  INFO 13568 --- [           main] com.rdpaas.platform.demo.RunApplication  : No active profile set, falling back to default profiles: default
2019-11-02 00:42:48.490  WARN 13568 --- [           main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'methodValidationPostProcessor' defined in class path resource [org/springframework/boot/autoconfigure/validation/ValidationAutoConfiguration.class]: Unsatisfied dependency expressed through method 'methodValidationPostProcessor' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.core.env.Environment' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
2019-11-02 00:42:48.499  INFO 13568 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2019-11-02 00:42:48.615 ERROR 13568 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of method methodValidationPostProcessor in org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration required a bean of type 'org.springframework.core.env.Environment' that could not be found.


Action:

Consider defining a bean of type 'org.springframework.core.env.Environment' in your configuration.

  如上很一般,谁都能够加上的类,就这样一个简朴的类,竟然能够直接致使springboot站不起来了,假如你认命了,实在也很好处置惩罚,你能够会换个名字尝尝,或许你压根就不会用到这个类,或许是你给@Component("env"),加个别号,能够就恰巧处置惩罚了这个题目,那末这时候你能够会当做springboot已划定了你不能运用症结字environment作为bean的称号,那末这个题目就变得一文不值了,因为你已认命了,不让我用我不必就好了,今后一生都不必这个类名就好了。眼不见心不烦,我用简称Env还来的费事点。不过我个人以为我们碰到困难应当迎难而上,不能随意认命,我们都是自满的顺序员。应当抱着愿望碰到困难的心态,主动去面临困难,多处置惩罚一些疑难杂症,用学问和履历武装本身,勤奋生长,走上人生顶峰!假如看到这里以为不认命的请随着我一同看看这个题目究竟为啥会涌现吧!

  接下来我们一步步来找到题目的泉源,为啥用了这个类,springboot就不举了?起首我们从启动的毛病提醒中找到唯一的症结信息:method methodValidationPostProcessor in org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration required a bean of type 'org.springframework.core.env.Environment' that could not be found。从这句话能够看出来在:org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration这个类中的这个要领:methodValidationPostProcessor 中须要一个:org.springframework.core.env.Environment类的对象作为参数,然则他找不到,看这个名字和我们本身定义的一样,先在idea中找到如上类的methodValidationPostProcessor要领的源码地点:

   为了考证图中的猜想,因为我这不是源码编译的,所以只能本身模拟这个类一样运用@Bean润饰一个要领看看是不是是内里的参数都是完整依据参数称号注入的(能够先诠释掉之前的Environment类消除谁人类的影响),以下

package com.rdpaas.platform.demo.env;
import org.springframework.stereotype.Component;
/**
 * 用作测试的bean
 * @author: rongdi
 * @date: 2019-11-2 0:12
 */
@Component
public class TestBean {
}
package com.rdpaas.platform.demo.env;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 模拟org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration
 * 运用@Configuration注解,而且供应一个static的@Bean润饰的要领
 * @author: rongdi
 * @date: 2019-11-2 0:11
 */
@Configuration
public class Config {

    @Bean
    public static TestBean create(TestBean tb) {
        System.out.println(tb);
        return tb;
    }

}

  如上我们运用默许的beanName为testBean的bean,然后Config类中注入的称号是tb运转springboot发明能够一般打印出tb对象,申明称号不一致一样能够注入胜利,所i有我们也许能够消除之前的猜想,想一想顶顶大名的springboot也不能够这么low逼吧!

  之前的猜想被颠覆,我们只能老老实实的运用debug一步步从springboot的进口一步步跟踪进去看看究竟啥时候最先报错的,这一步假如不熟悉spring代码的一定要耐烦一步步找找,以下

   之前对spring底层源码有一定相识的应当晓得spring是先把那些注解和xml声明的类加载到一个map里然后再举行初始化的,这个map就是beanDefinitionMap,一步步断点到spring最中心的要领refresh中

   当实行到上图蓝色位置时,也就是实行完invokeBeanFactoryPostProcessors(beanFactory)要领后,当前beanFactory里的beanDefinitionMap对象中找到了我们声明的environment对象的身影,以下

  断点的历程当中发明代码太多如果一步步找过去,很轻易就摒弃,所以我们再从上面的毛病日记找找有效信息,然后经由历程全局搜刮看看究竟时那里报出的毛病,如经由历程报错里的正告信息:expected at least 1 bean which qualifies as autowire candidate. Dependency annotations直接运用全局搜刮(前提时先断点跑一边,然后依据idea提醒下载好spring的源代码)

   点击上述要领后以下自始自终的打个断点从新跑一边看看

   这时候能够把断点打在if那行再进去看看是啥状况致使进入了这里,然后我们能够一定只如果if返回了true,就必定会致使报错,然后我们诠释掉本身的Environment类看看还可否进入到这里,经由历程诠释和不诠释的对照我们发明两种状况断点以后有以下差异

   所以题目的症结就是加入了本身的Environment类致使matchingBeans的map为空而产生了本例中的报错信息。

   接下来我们为了调试的效力,在每一个涌现beanName参数的要领打断点都运用这个前提断点,如今题目就回归到为啥加上了本身的Environment类后给matchingBeans供应数据的要领findAutowireCandidates为空了。自始自终的前提断点打到内里

   运用一样的体式格局在以下要领也加上前提断点,再次反复实行断点直到进去以下

   耐烦的再用如上一样体式格局进入这个要领,这里因为有多个类请运用F5(断点进入要领,能够快捷键不一样)

 

 

   从上看出,刚进去轮回的数组中显著有environment,然则效果为啥就成了空数组,进一步断点发明

   对照以上两个效果,很显著当我们本身添加了Environment类后,singletonObjects一定有一个移除操纵,然后我们找到一切singletonObjects.remove()的处所打一个前提断点:beanName.equals("environment"),很显著从逻辑上看,只需springboot不是悉数清空,必定会有一个 remove("environment")才诠释以上二者的差异。

  然后我们再在singletonObjects.put()相干的要领都打上一样的前提断点,放心大胆的继承从新断点实行一遍,第一次进入断点以下

   上图假如实行过addSingleton要领后this.singletonObjects中确切会放入以environment为key,以spring的StandardServetEnvironment为value的键值对进去,这里就不截图了,以免又要从新跑一次断点,直接点击左侧挪用栈谁人679行后以下:

  这里能够先记录下左侧环境对象究竟是在spring最主要的refresh要领的那一步

  依据上面得出的结论,之所以报错最基础的缘由就是这个singletonObjects找不到这个environment了,而这里有,所以一定有处所删除了这个key,因为这个map看起来云云主要,spring不会平白无故直接clear吧,所以只需找到唯一的删除key的体式格局singletonObjects.remove(),并打上上面说的前提断点,这一点上面实在说过了,那我们继承跑断点,直到找到在哪删除了这个key

 

 实在复盘一下全部调试历程,发明实在泉源以下

   实在我也不晓得这算不算是springboot的bug,照样实在只是一个症结字的限定,因为终究诠释权不在于我,就像mybatis中的xml里大于标记要用>不然他人基础剖析不了,从这一点来讲mybatis运用xml寄存sql实际上限定了我们运用大于小于等等这些标记的权利,只能用转义字符相似别号的东西替换。实在这里也是相似,也能够明白成人家体系须要,你要用这个请改个名字或许取个别号,比方@Component("env)。不过我照样愿望springboot能还我们运用单词的自在,愿望英文好的朋侪能够发发邮件让springboot团队斟酌下,哈哈!

末了来个篇中总结:

  1) 从文笔上来讲,自始自终的没有文笔,请列位大大见谅,真的全力了,怎样目不识丁!

  2) 从排版来讲,自始自终的没有排版,我是个纯手艺人,这些花狸狐哨的东西,真的一点不会,一样请列位见谅

  3) 从学问点来讲,实在这篇博客主如果给小白们分享一下看源码的技能和基础的调试才能,另有碰到题目的处置惩罚立场。起首从这篇文章中应当能清楚的get到逆向思索一步步找的题目的要领,其次应当能获取到一些断点调试源码的技能,末了也应当能学会要领挪用栈的作用。实在懂这三点基础就够了,spring这些源码是不是看过也不会影响你终究能找到这个题目的泉源这一效果,最多会影响你找到泉源的时候。

  4) 从专心水平来讲,这篇博客自以为是充足专心,周五晚上从放工回家一边一步步断点一遍写这篇博客,直到凌晨三点多才冲忙洗洗睡。文章里基础上把我晓得的关于这个学问点的一切东西经由历程清楚的图文体式格局一步步展示,本人酷爱手艺,也喜好分享手艺,愿望与宽大顺序猿们相濡以沫,共同进步!

  5) 从文章质量来讲,对大牛一文不值,对小白有一定协助,愿望大牛们多多见谅,不要喷我,有毛病的地方请多多斧正。

  选择打赏方式
微信赞助

打赏

QQ钱包

打赏

支付宝赞助

打赏

  移步手机端
一个一般类就醒目趴你的springboot,你信吗?

1、打开你手机的二维码扫描APP
2、扫描左则的二维码
3、点击扫描获得的网址
4、可以在手机端阅读此文章
未定义标签

本文来源:搜奇网

本文地址:https://www.sou7.cn/282238.html

关注我们:微信搜索“搜奇网”添加我为好友

版权声明: 本文仅代表作者个人观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。请记住本站网址https://www.sou7.cn/搜奇网。

发表评论

选填

必填

必填

选填

请拖动滑块解锁
>>