在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的一个最大策略:自定义组件用自己的,否则,使用默认的。

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @SpringBootConfiguration
  6. @EnableAutoConfiguration
  7. @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
  8. @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
  9. public @interface SpringBootApplication {


(一)@EnableAutoConfiguration


1.收集SPI里面配置的类

作用是开启自动配置功能.

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @AutoConfigurationPackage
  6. @Import(EnableAutoConfigurationImportSelector.class)
  7. public @interface EnableAutoConfiguration {
  8. }


@EnableAutoConfiguration注解里面会有@Import了一个AutoConfigurationImportSelector类,就会给AutoConfigurationImportSelector加入到Spring容器里面来,

AutoConfigurationImportSelector类实现了DeferredImportSelector接口,这个DeferredImportSelector的核心功能是通过SPI机制收集EnableAutoConfiguration为key的所有的类,然后通过 ConfigurationClassPostProcessor 这个类调用到该类中的方法,把收集到的类变成 beanDefinition 对象最终实例化加入到 spring 容器。


EnableAutoConfiguration 为 key 的所有类:该配置文件在spring-boot-autoconfigure jar 包中。

  1. # Auto Configure
  2. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  3. org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
  4. org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
  5. org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
  6. org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
  7. org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
  8. 省略..........

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).

  1. @Override
  2. public String[] selectImports(AnnotationMetadata annotationMetadata) {
  3. if (!isEnabled(annotationMetadata)) {
  4. return NO_IMPORTS;
  5. }
  6. AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
  7. .loadMetadata(this.beanClassLoader);
  8. // 获取所有的自动配置类
  9. AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
  10. annotationMetadata);
  11. return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
  12. }


这个类的selectImports()通过SpringFactoriesLoader得到了大量的配置类,而每一个配置类则根据条件化配置来做出决策,以实现自动配置。
这个类会扫描所有的jar包,将所有符合条件的@Configuration配置类注入的容器中,何为符合条件,看看META-INF/spring.factories的文件内容:

  1. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  2. org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
  3. org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
  4. org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration\
  5. .....

以DataSourceAutoConfiguration为例,看看Spring Boot是如何自动配置的:

  1. @Configuration
  2. @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
  3. @EnableConfigurationProperties(DataSourceProperties.class)
  4. @Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
  5. public class DataSourceAutoConfiguration {
  6. }

• @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两个方法的调用..

  1. /**
  2. * Return the imports defined by the group.
  3. * @return each import with its associated configuration class
  4. */
  5. public Iterable<Group.Entry> getImports() {
  6. for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
  7. this.group.process(deferredImport.getConfigurationClass().getMetadata(),
  8. deferredImport.getImportSelector());
  9. }
  10. return this.group.selectImports();
  11. }

AutoConfigurationEntry

需要加入到Spring容器的所有的类放入到configurations类里面,然后再封装成AutoConfigurationEntry对象.