在spring程序main方法中 添加@SpringBootApplication或者@EnableAutoConfiguration
会自动去maven中读取每个starter中的spring.factories文件 该文件里配置了所有需要被创建spring容器中的bean
自动装配原理
在SpringBoot里面不需要配置事务或者缓存或者切面或者mvc功能,可以直接拿来使用的.这些东西是SpringBoot给我们做好了.
在SpringBoot启动类上面有个核心注解@SpringBootApplication
@SpringBootApplication里面的@SpringBootConfiguration就是@Configuration,它是Spring框架的注解,标明该类是一个JavaConfig配置类。而@ComponentScan启用组件扫描.
@EnableAutoConfiguration注解表示开启Spring Boot自动配置功能,Spring Boot会根据应用的依赖、自定义的bean、classpath下有没有某个类 等等因素来猜测你需要的bean,然后注册到IOC容器中
自动配置原理:
1)、主程序类标注了@SpringBootApplication注解相当于标注了@EnableAutoConfiguration
2)、@EnableAutoConfiguration 开启SpringBoot的自动配置功能就会自动的将所有的自动配置类导进来
如:HttpEncodingAutoConfiguration(http编码的自动配置)
1)、@ConditionalOnXX根据当前系统环境判断我这个类的所有配置是否需要生效
2)、会发现这些配置类中使用@Bean给容器中放了好多组件,这些组件就生效;
3)、这些组件会从一个类中(配置文件属性值的封装类)获取到它应该使用的值是什么。比如HttpEncodingProperties获取charset
4)、这写配置文件值的封装类都是和配置文件一一绑定
@ConfigurationProperties(prefix = “spring.http.encoding”)
HttpEncodingProperties
使用心得:
1)、SpringBoot帮我们配好了所有的场景
2)、SpringBoot中会有很多的 xxxxAutoConfigurarion(帮我们给容器中自动配好组件)
3)、xxxxAutoConfigurarion给容器中配组件的时候,组件默认的属性一般都是从 xxxProperties中获取这些属性的值
4)、xxxProperties 是和配置文件绑定的(属性一一对应)
5)、我们改掉这些默认配置即可;
6)、如果默认的组件我们不用;
@Bean
@ConditionalOnMissingBean:容器中没这个组件
public InternalResourceViewResolver defaultViewResolver()
SpringBoot的一个最大策略:自定义组件用自己的,否则,使用默认的。
@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) })
public @interface SpringBootApplication {
(一)@EnableAutoConfiguration
1.收集SPI里面配置的类
作用是开启自动配置功能.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}
@EnableAutoConfiguration注解里面会有@Import了一个AutoConfigurationImportSelector类,就会给AutoConfigurationImportSelector加入到Spring容器里面来,
AutoConfigurationImportSelector类实现了DeferredImportSelector接口,这个DeferredImportSelector的核心功能是通过SPI机制收集EnableAutoConfiguration为key的所有的类,然后通过 ConfigurationClassPostProcessor 这个类调用到该类中的方法,把收集到的类变成 beanDefinition 对象最终实例化加入到 spring 容器。
EnableAutoConfiguration 为 key 的所有类:该配置文件在spring-boot-autoconfigure jar 包中。
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
省略..........
2.AutoConfigurationImportSelector 类作用
AutoConfigurationImportSelector 类中两个方法会被configurationClassPostProcessor 调到,一个是process方法,一个是selectImports方法
在这两个方法中完成了SPI类的收集,ConfigurationClassPostProcessor类只是把收集到的类变成了BeanDefinition并且加入到Spring容器里面.
selectImports
selectImports是ImportSelector接口的抽象方法这个方法主要作用就是收集需要导入的配置类,给这个返回的结果加入到Spring容器里面
selectImports方法是在AbstractApplicationContext.refresh()方法里面执行到,在DeferredImportSelectorGrouping#getImports方法被调用到,selectImports的作用是: 给process方法收集的@EnableAutoConfiguration类型的类加入到Spring容器里面(通过ConfigurationClassPostProcessor这个类变成BeanDefinition).
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
// 获取所有的自动配置类
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
这个类的selectImports()通过SpringFactoriesLoader得到了大量的配置类,而每一个配置类则根据条件化配置来做出决策,以实现自动配置。
这个类会扫描所有的jar包,将所有符合条件的@Configuration配置类注入的容器中,何为符合条件,看看META-INF/spring.factories的文件内容:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration\
.....
以DataSourceAutoConfiguration为例,看看Spring Boot是如何自动配置的:
@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
public class DataSourceAutoConfiguration {
}
• @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }):当Classpath中存在DataSource或者EmbeddedDatabaseType类时才启用这个配置,否则这个配置将被忽略。
• @EnableConfigurationProperties(DataSourceProperties.class):将DataSource的默认配置类注入到IOC容器中
在启动SpringBoot容器的时候会先执行到org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup#process,
这个process方法是在ConfigurationClassPostProcessor这个类调用过来的.
process
DeferredImportSelector接口里面的匿名接口Group的抽象方法
process做的事情:
1——————————-
拿到自动装配的所有实体类,通过SPI的加载方式给EnableAutoConfiguration为key的所有实现类进行过滤一下(因为不是所有的类需要加载到Spring容器里面)再封装成AutoConfigurationEntry对象,再加载到Spring容器(在ConfigurationClassPostProcessor类里面加到Spring容器的),完成实例化.
1——————————-
上述就是 EnableAutoConfiguration 为 key 自动配置类的收集过程。有自动配置类的收集并加入到 spring 容器
process和selectImports方法被调用到的地方
ConfigurationClassPostProcessor 类process和selectImports被调用的地方.
ConfigurationClassParser#processImports 调用
DeferredImportSelectorHandler#handle 方法,然后调用
DeferredImportSelectorGroupingHandler#processGroupImports方法调用
DeferredImportSelectorGrouping#getImports方法
在getImports方法内部完成了process和selectImports两个方法的调用..
/**
* Return the imports defined by the group.
* @return each import with its associated configuration class
*/
public Iterable<Group.Entry> getImports() {
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getImportSelector());
}
return this.group.selectImports();
}
AutoConfigurationEntry
需要加入到Spring容器的所有的类放入到configurations类里面,然后再封装成AutoConfigurationEntry对象.