一.序言

springBoot已经到2.3的版本,现在大多数的项目都在使用springBoot去构建项目。在日常使用中,大多数的程序猿都会惊叹到“猴赛雷”,都会被springBoot的技术折服,今天我就带大家去解开springBoot自动装配的面纱。
springBoot的技术栈比较多,比如tomcat的内嵌,dispatcherServlet的注入,springBoot的启动,springBoot的事件广播机制,配置文件加载优先级,项目类别的推断等等,但是自动配置是springBoot的核心技术,本猿认为是级别最高的知识点,其他的本猿也会在后面继续更新了。。。大家可以持续关注本猿。
在去解析自动装配之前,要必须有一定的知识储备和一些概念的东西,只有get到这些点的时候,才能行云流水般的感受到springBoot的精妙之处。

二.知识储备

1.自动装配是装配的什么(灵魂的拷问)?

spring的IOC是spring生态链的核心,我们所说的自动装配无非是不用我们手动去注入,在引入一个包(就是starter)的时候,他就自动帮我们注入到IOC容器中,我们直接使用就行了。例如我们依赖一个spring-boot-starter-kafka的包的时候,就直接可以使用KafkaTemplate,很神奇。总结:自动装配就是spring容器启动后,一些自动配置类就自动装配的IOC容器中,不需要我们手动去注入。

2.what is SPI?

SPI是server provider interface 的简写,字面意思是服务发现接口,我理解就是第三方拓展API,他是java提出的,即开箱即用的思想。在spring的生态中已经运用得非常多,比如springMVC中官方推荐的去web.xml的方式,用一个onStart的方法就将dispatcherServlet到IOC的容器中,这也是利用了tomcat的SPI。在springBoot中,当我们加一个starter的包,spring将帮我们注入了一些类。你删掉包后,spring就不会注入。不会产生任何的影响,这就是SPI的思想,拆箱即用。

3.spring3.0和springBoot之间发生了什么?

其实在spring3.0已经有了去配置文件的方式–javaConfig,他是一整套的解决配置文件的方案,我们只需要将注入IOC容器的对象用类的方式表现出来,也可以做到无配置。可能很多类似于我的这种程序猿直接从xml进化到springBoot,javaConifg这种产物还没来得及去使用。springBoot就是利用了spring的javaConfig的形式再演化到现在配置类都帮我们写好了,就是在starter的包中,减少了更多的工作。不仅仅是自动装配,springBoot很多的功能都是在spring的生态链进行扩展。可见一个优秀的框架的扩展能力是多么的强大。

4.ImportSelector的作用?

ImportSelector也是spring中6大扩展点之一,本猿也是从spring的源码一路走过来的,所以对spring的IOC的流程比较熟悉,他的原理比较复杂,在这儿我们只研究他的作用,心有余而力不足啊,以后会更新的。ImportSelector接口中有一个方法selectImports,返回值是一个String[],我们只要返回类的类路径,就会被spring给实例。有童鞋可能会问,为什么不在configuration的配置文件中用@bean的方式注入,要用这种方式,用这种方式我们可以在方法中写一些逻辑去选择性的一次性注入很多的类,这就是springBoot使用的原因。

以上是必须的知识储备,以下还有非必须的知识点,通过上面的知识点,可以将springBoot的原理走通,下面是自动装配过程中运用到其他的技术,也非常的重要,特别是第一点。

5.配置文件的装载?

我们在yaml可以设置很多的配置项,这些配置项是从哪里来的呢?在springBoot的底层怎么用的?我们可以分析下我们配置tomcat的一些配置来分析。
我们能配置这些配置项,是因为在sprigBoor的包中有一个类,@ConfigurationProperties定义了他的前缀,类中的属性就是我们可以在配置文件种配置的,必须提供set和get方法。如果我们要自定义自己的配置文件,一定要加spring-boot-configuration-processor这个包,在配置文件中才会有提示。

下面是怎么去使用这个对象,我们需要注解@EnableConfigurationProperties,在使用的方法,直接传入这个参数,就直接可以使用,这完全是spring在实例化的过程中帮我们做到的。

6.springBoot的条件注入

这个是springBoot经常使用到的一个技术点,他是一个注解,在springBoot中开发了很多,比如ConditionalOnBean,ConditionalOnProperties等将近10个这样的springBoot注解。他的作用是满足了某个条件被注解的类或者方法返回的对象(@Bean)才能被spring实例化,不满足就不实例化。当前这个注解也可以加在类和方法上。那这个条件的逻辑是写在什么地方的呢?我们来剖析一个比较常用的@ConditionalOnProperties注解吧。

这是我自己实现的一个实例,配置文件中有cw.author的配置项,这个PersonService才会被实例。亲测可用。

注解下又有一个注解,@Conditional这个注解是spring开发的,关键在于OnPropertyCondition的类中。

这个类继承了SpringBootCondition,这个类只不过是springBoot的抽象类,IOC在实例化的过程中调用了matches方法,最终还是调用子类的getMatchOutcome方法。这又跟spring实例化有关,可见知识连贯的重要性。我教大家一个方法,在matches方法中打一个断点,根据调用栈可以分析出spring在实例化中调用shouldSkip方法调用过来的,只有matches方法返回true,对象才会被实例。这也是@condition注解的原理。

三.正篇

用了很大篇幅去介绍了这么多知识点,为的就是更好的去理解自动装配的原理。如果大家都get到了上面的点,那么自动装配的原理就会变得像喝水一样简单(致敬子路老师)。

1.starter开箱即用的原理

之前介绍了SPI,加入一个starter他就可以自动配置。原理是springBoot在META_INF中有一个配置文件spring.factories,需要被spring实例的配置对象,都会被定义在里面。我们自定以一个starter,我们也可以按照约定在spring.factories加入自己需要配置的装配类,也会被spring给加载。这就是自动装配的第一步。

2.官方的starter和自定义starter的区别?

在springBoot官方网站中,**有介绍如果是自己开发的starter以spring-boot-starter-xxx命名,自己开发的以xxx-spring-boot-starter命名。**上面我们说了自定义的starter自己在META_INF的spring.factories中定义自己的装配类。但是官方的有点区别,就是他把自己生态的starter都定义autoconfigure包的spring.factories中,毕竟是自己的东西嘛,可以理解。

3.springBoot自配配置的入口?

我们从@SpringBootApplication注解开始,我们在启动类上配上这个注解,就可以完成自动配置的功能。我们看看这个注解下面有什么?

下面有这么多的注解,自动配置主要是@EnableAutoConfiguration起作用,我们再往下看。

有没有看到我们熟悉的ImportSelector,加载自动配置类就是在这个类完成的。

spring的扩展点,ImportSelector字面意思理解:选择注入。我们也可以理解为我们完成一个功能时需要依赖一些其他类。比如我们启动springBoot项目时,需要依赖这些自动配置类。spring会调用selectImports方法,把返回的自动配置类加入到IOC的容器中。

这个方法就是去加载自动配置的类。最后以AutoConfiguationEntry去封装起来,spring最喜欢干的事。

springFactories就是去加载spring.factories文件中org.springframework.boot.autoconfigure.EnableAutoConfiguration的类路径。

3.自配装配的流程

上面自动配置的类已经完成了实例化,下面我们主要分析下自动配置类有什么?
这是spring官方的kafka自动配置的类。他被定义在autoconfiguration的包里面。

童鞋们可以思考下为什么会是红色的?
自动配置注解了@configuration,spring会把他当成一个普通的配置类来处理。他会去实例化KafkaTemplate对象。@ConditionOnMissBean注解表示IOC容器中没有这个对象才进行实例化,原理上面已经讲过了。
@EnableConfigurationProperties注解会去配置使用这个配置文件装配对象KafkaProperties。spring会自动注入到下面的属性中,我们可以直接使用。

下面是我们可以yaml配置文件中可以配置那些kafka的配置项,当然要引入kafka的starter包才行。

三.完结

这时,kafkaTempalte就在我们spring的容器中,我们在可以直接autowire注入直接使用。省去了我们之前繁琐的配置和繁琐的手动实例化对象的过程。这就是自动配置的魅力。springBoot非常依赖spring的生态。严格说就是在spring的基础上进行扩展。所以很多知识都是要融合贯通,大家也可以去学习学习spring的IOC的实例化过程,可能对理解有很大的帮助。
以上是springBoot自动配置的全部过程,全部自己的理解,大家可以一起讨论学习,如果阐述有误,欢迎在评论指正。

更多推荐

《面试无忧》--最详细的springBoot自动配置原理解析