一、开篇 在平时的开发过程中用的最多的莫属springboot了,都知道springboot中有自动注入的功能,在面试过程中也会问到自动注入,你知道自动注入是怎么回事吗,springboot是如何做到自动注入的,自动注入背后的原理是什么,今天来分析下springboot的自动注入,希望这篇文章可以解除大家心中的疑惑。二、详述2。1、什么是自动注入 天天将自动注入,你真正明白自动注入是怎么回事吗?举个例子来说,我们要在springboot中使用mybatis,之前的做法是什么? 1、引入依赖; 2、在配置文件中配置配置类; 3、写mybatis的配置文件或注解; 在springboot中这个步骤就减少了,减少的是第二步,不用再写一堆配置类了,步骤简化为: 1、引入依赖; 2、写mybatis的配置文件或注解; 也就是说无需再搞配置类了,就比如之前的SqlSessionFactoryBean,现在不用配置了,springboot为我们做了这些工作,现在看springboot引入mybatis需要加入的依赖,!mybatis的依赖dependencygroupIdorg。mybatis。spring。bootgroupIdmybatisspringbootstarterartifactIdversion2。1。3versiondependency!mysql的驱动程序dependencygroupIdmysqlgroupIdmysqlconnectorjavaartifactIdversion8。0。26versiondependency 我们加入mybatis和数据库的驱动依赖,因为mybatis要使用数据库连接,所以这里少不了mysql的数据库驱动。重点看mybatis的这个依赖和之前的是不一样的,这个是mybatisspringbootstarter,再看这个依赖中都有哪些jar, 除了常见的mybatis及mybatisspring还有一个mybatisspringbootautoconfigure,这个就是今天的主角。2。2、springboot读取spring。facotries文件(可跳过该节) 前边说到今天的主角是mybatisspringbootautoconfigure,其实还有很多这样的依赖,大多数第三方自己实现的都会有这样一个依赖比如,前边自己实现的starter中就有这样一个customerspringbootautoconfigurer,还有很多都是springboot自己实现的,所以无需这样的依赖。 要想知道springboot是如何进行自动注入的,唯一的方式是debug,现在开始debug之旅吧。2。2。1、SpringApplication构造方法 springboot的启动很简单,就是下面这样一行代码SpringApplication。run(BootServer。class); 要跟着这样一行代码走下去,追踪到了这样一句,publicstaticConfigurableApplicationContextrun(Classlt;?〔〕primarySources,String〔〕args){returnnewSpringApplication(primarySources)。run(args);} 可以看的会new一个SpringApplication的实例,然后再调用其run方法,先看下new方法做了什么,最终调用的是下面的构造方法,publicSpringApplication(ResourceLoaderresourceLoader,Classlt;?。。。primarySources){this。resourceLoaderresourceLoader;Assert。notNull(primarySources,PrimarySourcesmustnotbenull);this。primarySourcesnewLinkedHashSet(Arrays。asList(primarySources));this。webApplicationTypeWebApplicationType。deduceFromClasspath();设置初始化器,很重要setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer。class));设置监听器,很重要setListeners((Collection)getSpringFactoriesInstances(ApplicationListener。class));this。mainApplicationClassdeduceMainApplicationClass();} 我在上面做了注释,重点看注释部分的代码;2。2。2、setInitializers()方法 该方法从方法名上看是要设置初始化器,其中getSpringFactoriesInstances(ApplicationContextInitializer。class)是重点。其方法定义如下,privateTCollectionTgetSpringFactoriesInstances(ClassTtype,Classlt;?〔〕parameterTypes,Object。。。args){ClassLoaderclassLoadergetClassLoader();UsenamesandensureuniquetoprotectagainstduplicatesSpringFactoriesLoader。loadFactoryNames是重点SetStringnamesnewLinkedHashSet(SpringFactoriesLoader。loadFactoryNames(type,classLoader));ListTinstancescreateSpringFactoriesInstances(type,parameterTypes,classLoader,args,names);AnnotationAwareOrderComparator。sort(instances);returninstances;} 看SpringFactoriesLoader。loadFactoryNames方法,publicstaticListStringloadFactoryNames(Classlt;?factoryType,NullableClassLoaderclassLoader){StringfactoryTypeNamefactoryType。getName();loadSpringFactories(classLoader)方法是重点returnloadSpringFactories(classLoader)。getOrDefault(factoryTypeName,Collections。emptyList());} 把断点放在loadSpringFactroies方法内, 从上面的debug结果可以看到使用AppClassLoader读取FACTORIESRESOURCELOCATION处的资源,AppClassLoader大家都很熟悉,就说应用类加载器,常量FACTORIESRESOURCELOCATION指的是,Thelocationtolookforfactories。pCanbepresentinmultipleJARfiles。publicstaticfinalStringFACTORIESRESOURCELOCATIONMETAINFspring。factories; jar下的METAINFspring。factories文件,也就是说要读取项目中jar包中的METAINFspring。factories文件的内容,我在springboot2。3。3。RELEASE。jar中找到这样一个文件,仅截个图,详细内容可以自己查看, 可以看到是一些列的键值对,我们看下loadSpringFactories方法最后的返回值, 这个返回值是,项目中所有jar下METAINFspring。factories文件中的键值对组成的map。回到loadFactoryNames方法处 该方法需要的是key为org。springframework。context。ApplicationContextInitializer的value,该value的值有这样7个 这样我们把setInitializers方法就分析完了,其主要就是从jar包中的METAINFspring。factories文件中获取org。springframework。context。ApplicationContextInitializer对应的值。下面看setListeners方法2。2。3、setListeners()方法 该方法和setInitializers方法是类似的, 重点是其参数不一样,该方法的参数是ApplicationListener。class,也就是要找出org。springframework。context。ApplicationListener在spring。factories中的配置, 本人核实过这些的确是从spring。factories文件中读取的,和其内容是一致的。 写到这里其实和自动注入没有关系,如果说有关系的话是,这里认识了一个关键的类SpringFactoriesLoader,该类的作用就是读取jar包中METAINFspring。facotries文件的内容。在后边的自动注入中还会出现该类的影子。继续向前。2。3、自动注入的原理2。3。1、SpringBootApplication注解 在启动springboot程序的时候在程序的入口都会有写上SpringBootApplication的注解,packagecom。my。template;importorg。springframework。boot。SpringApplication;importorg。springframework。boot。autoconfigure。SpringBootApplication;启动类date20226321:32SpringBootApplicationpublicclassBootServer{publicstaticvoidmain(String〔〕args){try{SpringApplication。run(BootServer。class);}catch(Exceptione){e。printStackTrace();}}} 看下该注解的定义, 在该注解上还有SpringBootConfiguration、EnableAutoConfiguration、ComponentScan三个注解,今天重点看EnableAutoConfiguration注解。2。3。2、EnableAutoConfiguration注解 该注解便是自动注入的核心注解, 重点是该注解上的下面这句话,Import(AutoConfigurationImportSelector。class) 看下AutoConfigurationImportSelector类,该类中有这样一个方法,和自动注入是相关的,protectedListStringgetCandidateConfigurations(AnnotationMetadatametadata,AnnotationAttributesattributes){ListStringconfigurationsSpringFactoriesLoader。loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());Assert。notEmpty(configurations,NoautoconfigurationclassesfoundinMETAINFspring。factories。Ifyouareusingacustompackaging,makesurethatfileiscorrect。);returnconfigurations;} 很属性的SpringFactoriesLoader类又出现了,还是很熟悉的loadFactoryNames方法,这次的方法参数是getSpringFactoriesLoaderFactoryClass()方法,Returntheclassusedby{linkSpringFactoriesLoader}toloadconfigurationcandidates。returnthefactoryclassprotectedClasslt;?getSpringFactoriesLoaderFactoryClass(){returnEnableAutoConfiguration。class;} 所以SpringFactoriesLoader。loadFactoryNames是要从METAINFspring。factories中获取key为org。springframework。boot。autoconfigure。EnableAutoConfiguration的value,这里可以看到有很多,从中还可以找到我自定义的和myatis的。 也就是说要把这些配置类加到spring的容器中。现在有个问题这些配置都会生效吗?2。3。3、这些配置类都会生效吗? 上面说到自动配置会加载很多的配置类,但是这些类都会生效吗?答案是不会的,只会在特定情况下生效,以MybatisAutoConfiguration为例, 可以看的该类上有很多注解, ConditionalOnClass,当类路径中存在某个类标识该注解的类才会生效,也就是只有存在SqlSessionFactory、SqlSessionFactoryBean才会解析MybatisAutoConfiguration类。换句话说,要有mybatis、mybatisspring的jar包。 ConditionaleOnSigleCanidate,需要一个单例bean EnableConfigurationProperties读取配置文件,也就是application。properites AutoConfigureAfter自动配置在某个类之后 现在我们知道了一个XXAutoConfiguration类是否会生效还要看其上面的注解是怎么定义的。三、总结 本文主要分析了springboot的自动注入原理, 1、注解SpringBootApplication中含有三个注解,其中EnabelAutoConfiguration和自动配置有关; 2、EnableAutoConfiguration会读取所有jar下METAINFspring。factories文件的内容,获取org。springframework。boot。autoconfigure。EnableAutoConfiguration的配置,把这些配置注入到容器; 3、EnableAutoConfiguration注入的类是否生效,需要看其上面的注解,主要配合ConditionaleXXX注解使用;