在springboot的开发中,starter是一个核心的配置,只需要引入对应模块的starter,然后在application.properties中引入对应的配置项,就可以开发业务逻辑了。
这一切都归功于springboot的自动配置的能力。
一个问题引出自动装配:
在创建一个SpringBoot项目后,为什么一个配置文件都没有,他就能跑起来?
首先。找到整个项目的入口main方法, 会看到一个 @SpringBootApplication 注解。此注解的作用就是作为Spring的入口,而且他是一个复合注解。
点进去发现:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM,
classes = AutoConfigurationExcludeFilter.class) })
注意其中比较重要的三个:
- @SpringBootConfiguration 继承自@Configuration,其实它就是 JavaConfig 形式的 SpringIOC 容器的配置类,也是 SpringBoot 推荐使用配置形式,所以主程序类标注了 @SpringBootConfiguration 注解,其本身也就是一个配置类。二者功能也一致,标注当前类是配置类,并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到srping容器中,并且实例名就是方法名。
- @EnableAutoConfiguration 的作用启动自动的配置,@EnableAutoConfiguration注解的意思就是Springboot根据你添加的jar包来配置你项目的默认配置,比如根据spring-boot-starter-web ,来判断你的项目是否需要添加了webmvc和tomcat,就会自动的帮你配置web项目中所需要的默认配置。
- @ComponentScan 扫描当前包及其子包下被@Component,@Controller,@Service,@Repository注解标记的类并纳入到spring容器中进行管理。是以前的<context:component-scan>(以前使用在xml中使用的标签,用来扫描包配置的平行支持)。所以本demo中的User为何会被spring容器管理
就是由于@EnableAutoConfiguration 的存在。使得SpringBoot可以自动配置 (约定优于配置) 。
点击进入@EnableAutoConfiguration的实现:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
//...
}
会发现@AutoConfigurationPackage 这个注解。 这个注解很关键。此注解会把主配置类 xxxxApplication.java类所在的包及其子包全部纳入Spring容器中。
传统我们需要手动在xml配置配置扫描解析器 <context:component-scan base-package> ,但是在SpringBoot中就省掉了这一步。
上面说的都是引入的自己的写的包。而这个@Import(AutoConfigurationImportSelector.class)注解,就是引入第三方的jar或者配置文件,进入AutoConfigurationImportSelector类,会发现此类存在一个selectImports() 方法,用来引入第三方jar和配置。其中有个重要的文件:
依赖库中找到 spring-boot-autoconfigure-2.1.4.RELEASE.jar 这个jar,打开后里边有META-INF文件夹,此文件夹下有spring.factories文件。里面就声明了所有需要的第三方依赖,并通过@EnableAutoConfiguration开启使用。
费这么大劲就为了引出了这个文件,而这个文件,就是自动装配的关键。
自动装配原理:
首先在刚才的spring.factories文件里,随便点进去一个 **AutoConfiguration类:
@Configuration
@AutoConfigureBefore(JmsAutoConfiguration.class)
@ConditionalOnClass(JmsTemplate.class)
@ConditionalOnMissingBean(ConnectionFactory.class)
@Conditional(JndiOrPropertyCondition.class)
@EnableConfigurationProperties(JmsProperties.class)
public class JndiConnectionFactoryAutoConfiguration {
// Keep these in sync with the condition below
private static final String[] JNDI_LOCATIONS = { "java:/JmsXA",
"java:/XAConnectionFactory" };
//之后的代码省略
会发现很多以 @ConditionalOn 开头的注解。
简单来说:
在spring.factories文件中的每一个 ****AutoConfiguration 中,都有很多条件注解如:@ConditionalOn***** 存在
当这些条件都将满足时,则此自动装配生效。
生效后还可以手动修改之:
在全局application.properties 文件中,以: ****AutoConfiguration的prefix.属性名 = 自定义值的方式修改。
全局配置文件中的key其实就是prefix+属性名。
即:根据当前不同的条件判断,决定 HttpEncodingAutoConfiguration 这个配置类是否生效。 一但这个配置类生效;这个配置类就会给容器中添加各种组件,这些组件的属性是从对应的 HttpEncodingProperties 类中获取的,这些类里面的每一个属性又是和配置文件绑定的。
图为Conditional相关注解: