美文网首页
SpringBoot自动装配原理

SpringBoot自动装配原理

作者: 野生Java程序员 | 来源:发表于2020-06-15 10:23 被阅读0次

    © 本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。转载请保留原文链接及作者

    不翼而飞的xml配置

    曾经在学习Spring框架的时候,需要繁琐的xml配置或者注解,稍不注意还很容易出错,码农需要花费很多的时间来进行xml配置。直到有一天,SpringBoot出现了,犹如天使一般,码农再也不用进行繁琐的xml配置了,这一切都是来自于SpringBoot的魔法——自动配置
    Springboot遵循“约定优于配置”的原则,使用注解对一些常规的配置项做默认配置,减少或不使用xml配置,让你的项目快速运行起来。Springboot还为大量的开发常用框架封装了starter,如今引入框架只要引入一个starter,你就可以使用这个框架,只需少量的配置甚至是不需要任何配置。

    SpringBoot自动配置原理

    1. @SpringBootApplication

    SpringBoot启动的时候加载主配置类(@SpringBootApplication),开启了自动配置功能 @EnableAutoConfiguration。
    @SpringBootApplication是一个派生注解,里面包含了三个注解@SpringBootConfiguration、@EnableAutoConfiguration和@ComponentScan。

    @SpringBootApplication
    @EnableSwagger2
    public class HzmokoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(HzmokoApplication.class, args);
        }
    
    • @SpringBootConfiguration:我们点进去以后可以发现底层是Configuration注解,说白了就是支持JavaConfig的方式来进行配置(使用Configuration配置类等同于XML文件)。
    • @EnableAutoConfiguration:开启自动配置功能(后文详解)
    • @ComponentScan:这个注解,学过Spring的同学应该对它不会陌生,就是扫描注解,默认是扫描当前类下的package。将@Controller/@Service/@Component/@Repository等注解加载到IOC容器中。

    2. @EnableAutoConfiguration

    我们知道SpringBoot可以帮我们减少很多的配置,也肯定听过“约定大于配置”这么一句话,那SpringBoot是怎么做的呢?其实靠的就是@EnableAutoConfiguration注解。

    简单来说,这个注解可以帮助我们自动载入应用程序所需要的所有默认配置
    我们点进去看一下,发现有两个比较重要的注解:

    • @AutoConfigurationPackage:自动配置包
    • @Import:给IOC容器导入组件

    2.1 @AutoConfigurationPackage

    有人将这个@AutoConfigurationPackage注解解释成自动配置包,我们也看看@AutoConfigurationPackage里边有什么:

    我们可以发现,依靠的还是@Import注解,再点进去查看,我们发现重要的就是以下的代码:

    
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata,
            BeanDefinitionRegistry registry) {
        register(registry, new PackageImport(metadata).getPackageName());
    }
    
    

    默认的情况下就是将:主配置类(@SpringBootApplication)的所在包及其子包里边的组件扫描到Spring容器中。

    • 看完这句话,会不会觉得,这不就是ComponentScan的功能吗?这俩不就重复了吗?

    我开始也有这个疑问,直到我看到文档的这句话:

    it will be used when scanning for code @Entity classes. It is generally recommended that you place EnableAutoConfiguration (if you're not using @SpringBootApplication) in a root package so that all sub-packages and classes can be searched.

    比如说,你用了Spring Data JPA,可能会在实体类上写@Entity注解。这个@Entity注解由@AutoConfigurationPackage扫描并加载,而我们平时开发用的@Controller/@Service/@Component/@Repository这些注解是由ComponentScan来扫描并加载的。

    • 简单理解:这二者扫描的对象是不一样的。

    2.2 @Import(EnableAutoConfigurationImportSelector.class)

    我们来看以下EnableAutoConfigurationImportSelector的源码,它继承了AutoConfigurationImportSelector








    通过源码分析:
    AutoConfigurationImportSelector的selectImports()方法通过SpringFactoriesLoader.loadFactoryNames()扫描所有具有META-INF/spring.factories的jar包。spring-boot-autoconfigure-x.x.x.x.jar里就有一个这样的spring.factories文件。

    这个spring.factories文件也是一组一组的key=value的形式,其中一个key是EnableAutoConfiguration类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表,这些类名以逗号分隔,如下图所示:


    spring-boot-autoconfigure jar包结构图.png
    spring.factories文件结构.png

    这个@EnableAutoConfiguration注解通过@SpringBootApplication被间接的标记在了Spring Boot的启动类上。在SpringApplication.run(...)的内部就会执行selectImports()方法,找到所有JavaConfig自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中。

    自动配置生效

    每一个XxxxAutoConfiguration自动配置类都是在某些条件之下才会生效的,这些条件的限制在Spring Boot中以注解的形式体现,常见的条件注解有如下几项:

    • @ConditionalOnBean:当容器里有指定的bean的条件下。
    • @ConditionalOnMissingBean:当容器里不存在指定bean的条件下。
    • @ConditionalOnClass:当类路径下有指定类的条件下。
    • @ConditionalOnMissingClass:当类路径下不存在指定类的条件下。
    • @ConditionalOnProperty:指定的属性是否有指定的值,比如@ConditionalOnProperties(prefix=”xxx.xxx”, value=”enable”, matchIfMissing=true),代表当xxx.xxx为enable时条件的布尔值为true,如果没有设置的情况下也为true。

    以ServletWebServerFactoryAutoConfiguration配置类为例,解释一下全局配置文件中的属性如何生效,比如:server.port=8081,是如何生效的(当然不配置也会有默认值,这个默认值来自于org.apache.catalina.startup.Tomcat)。



    在ServletWebServerFactoryAutoConfiguration类上,有一个@EnableConfigurationProperties注解:开启配置属性,而它后面的参数是一个ServerProperties类,这就是习惯优于配置的最终落地点。



    在这个类上,我们看到了一个非常熟悉的注解:@ConfigurationProperties,它的作用就是从配置文件中绑定属性到对应的bean上,而@EnableConfigurationProperties负责导入这个已经绑定了属性的bean到spring容器中(见上面截图)。那么所有其他的和这个类相关的属性都可以在全局配置文件中定义,也就是说,真正“限制”我们可以在全局配置文件中配置哪些属性的类就是这些XxxxProperties类,它与配置文件中定义的prefix关键字开头的一组属性是唯一对应的。

    至此,我们大致可以了解。在全局配置的属性如:server.port等,通过@ConfigurationProperties注解,绑定到对应的XxxxProperties配置实体类上封装为一个bean,然后再通过@EnableConfigurationProperties注解导入到Spring容器中。

    而诸多的XxxxAutoConfiguration自动配置类,就是Spring容器的JavaConfig形式,作用就是为Spring 容器导入bean,而所有导入的bean所需要的属性都通过xxxxProperties的bean来获得。

    可能到目前为止还是有所疑惑,但面试的时候,其实远远不需要回答的这么具体,你只需要这样回答:

    Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而XxxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。
    通过一张图标来理解一下这一流程:


    相关文章

      网友评论

          本文标题:SpringBoot自动装配原理

          本文链接:https://www.haomeiwen.com/subject/uvzqxktx.html