前言
在使用传统的 Spring 去做 Java EE 应用开发时,在项目中会出现大量的 XMl配置文件,使 Java EE 项目变得笨重且繁琐,从而导致开发和部署上的效率降低。
Spring Boot 的出现就是简化 Spring 应用的搭建及开发过程。它使用特定的方式来进行配置,从而使开发人员不在需要样板化的配置,也就是说 Spring Boot 并不是什么新的框架。它只是在底层帮我们做好了 Spring 的配置,下面我来详细说明 Spring Boot 是如何自动装配的。
自动配置源码分析
1)Spring Boot 项目中都会使用 @SpringBootApplication 注解来标识当前这个类是主程序。
在主程序的 main() 方法中使用 SpringApplication.run(Class<?> primarySource, String… args) 启动主程序,它的返回值是我们 IOC 的容器。
2)进入 @SpringBootApplication 注解内部,可以发现此注解其实是复合型注解,它是由这三个重要的注解组成的:@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan
- @ComponentScan 注解:主要是定义扫描的路径从中找出标识了需要装配的类,把它装配到 Spring 的 Bean 容器中。
在web开发中我们经常使用:@Controller、@Service、@Repository 注解,查看源码会发现它们有一个共同的注解 @Component。而 @ComponentScan 注解默认识别这几种注解并加入到 Bean 容器中。
-
@SpringBootConfiguration 注解:内部使用了 @Configuration 注解来标识当前这个类是一个配置类。
- @SpringBootConfiguration 注解是 @Configuration 注解的派生注解,其功能是一致的。
- @SpringBootConfiguration 是 SpringBoot 的注解,而 @Configuration 则是 Spring 原生注解。
-
@EnableAutoConfiguration 注解:这就是与自动配置有关的注解,也是复合型注解它是有两个重要的注解组成的:@AutoConfigurationPackage、@Import。
-
@AutoConfigurationPackage 注解:指定了默认的规则。它的内部使用 @Import 默认将 Registrar 类作为 Bean 组件引入。
并且指定与当前主程序同级或一下的所有包。打开 Registrar 类,在 registerBeanDefinitions() 方法中打上断点使用 debug 运行,选中new PackageImports(metadata).getPackageNames()
进行计算。
-
@Import(AutoConfigurationImportSelector.class) 注解:默认将 AutoConfigurationImportSelector 类作为 Bean 组件导入,是整个自动配置的核心。进入 AutoConfigurationImportSelector 类找到 getAutoConfigurationEntry() 方法,此方法是个容器中批量导入一些组件。
给List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)
打上断点,从中我们可以发现它获取了所有需要导入到容器中的配置类。
进入到 getCandidateConfigurations(annotationMetadata, attributes)) 方法。
进入到 loadFactoryNames() 方法。
利用工厂加载 loadSpringFactories() 从 META-INF/spring.factories 位置来加载一个文件,默认扫描我们当前系统里面所有 META-INF/spring.factories 位置的文件。
我们可以在 spring-boot-autoconfigure-2.5.3.jar 包里 META-INF 下的 spring.tactories 文件中查看 Spring Boot 启动时就给我们的容器中加载的所有配置类。
这么多的配置类我们全部都用上了吗,其实在自动装配启动的时候只是全部默认加载,并没有全部装配,因为所有的 xxxAutoConfiguration 自动配置类都使用了条件配置注解 @Conditional 及其子注解,从而实现按需配置。举例一:DispatcherServletAutoConfiguration 自动配置类(生效)。
进入源码,可以发现 @ConditionalOnClass(DispatcherServlet.class) 注解,此注解要求必须有 DispatcherServlet 类,如果没有则该自动配置类失效。
举例二:RedisAutoConfiguration 自动配置类(无效)。
在源码中可以看到 @ConditionalOnClass(RedisOperations.class) 注解,当我们有 RedisOperations 类时才会生效。
修改默认配置 所有的自动配置类中可以看到 @EnableConfigurationProperties(xxxProperties.class) 注解,在xxxProperties.class 类中设置的是自动配置类的默认属性。
举例:MultipartAutoConfiguration 文件上次自动配置类
进入 MultipartProperties 类,可以看到这里面都默认设置了属性值。如果我们需要定制自动配置类属性值,只需要在自己项目下的 application.yaml 或是 application.properties 配置文件设置即可。
在定制自动配置类属性值之前我可以看到原生的 MultipartProperties 类中有 @ConfigurationProperties() 注解,它默认设置 prefix = “spring.servlet.multipart” 前缀,当我们在定制属性值是必须使用前缀加上字段名设置。
在 application.yaml 定制 enabled 属性值为 false,它会把默认的设置覆盖掉。
-
总结:
- Spring Boot 先加载所有的自动配置类 xxxAutoConfiguration。
- 每个自动配置类根据 @Conditional 条件注解来按需加载。
- 每个自动配置类默认绑定 @EnableConfigurationProperties 注解中的 xxxProperties 类中的属性值。
- 如果在 application.yaml 或 applicaton.properties 配置中定制属性值,那么它会覆盖原有的 xxxProperties 类中的属性值。
- 也可以定制配置,只需要使用 @Bean 注解替换掉底层的组件即可。