最好自己跟着源码看,懒得看的可以直接看后面的总结
springboot的自动配置要从我们的启动类注解@SpringBootApplication
说起
进入@SpringBootApplication注解中:
@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 {
重要注解有三个
@SpringBootConfiguration
:内部就是一个@Configuration注解,就是让该类支持java类配置(用java类配置代替xml配置形式)@ComponentScan
:就是注解扫描,默认扫描当前类下的包,会把在@Component注解下的类的注册成bean加载到spring容器中,如@Controller、@Service、@Repository、@Configuration等注解@EnableAutoConfiguration
:这个就是完成我们自动配置的关键注解
进入@EnableAutoConfiguration中:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
这里有两个重要的注解@AutoConfigurationPackage
与@Import
1.进入@AutoConfigurationPackage
中:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
这里引入了一个AutoConfigurationPackages类的内部Registrar类,进入该类:
/**
* {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
* configuration.
*/
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImport(metadata));
}
}
同时在AutoConfigurationPackages类中也有一句注释:
/**
* Class for storing auto-configuration packages for reference later (e.g. by JPA entity
* scanner).
*
* @author Phillip Webb
* @author Dave Syer
* @author Oliver Gierke
* @since 1.0.0
*/
public abstract class AutoConfigurationPackages {
意思是 这个类是用来存储自动配置的包供以后引用
,简单来说就相当于@ComponentScan
注解扫描。
那为什么在已有@ComponentScan
的情况下还需要这个扫描呢?
注释中还有一个例子:(e.g. by JPA entity scanner).
就是如果使用了Spring Data JPA那么在实体类上的@Entity
就会使用这个
@AutoConfigurationPackage
注解来进行扫描,所以这两个注解扫描的对象不同。
2.进入@Import(AutoConfigurationImportSelector.class)引入的类中:
进入该getAutoConfigurationEntry()
方法:
继续进入getCandidateConfigurations()
方法:
进入loadFactoryNames()
方法:
那么key值factoryClassName
是什么呢?
就是loadFactoryNames()
方法的第一个参数getSpringFactoriesLoaderFactoryClass()
方法的返回值的getName()
值:
所以key值为EnableAutoConfiguration
那么value呢?
value值就是从jar包中的META-INF/spring.factories文件中加载:
spring.factories文件:
总结
- @SpringBootApplication注解中包含了
@EnableAutoConfiguration
注解,该注解中引入了一个AutoConfigurationImportSelector
类, AutoConfigurationImportSelector
类会去META-INF/spring.factories
文件内将里面的内容封装在Map<String, List<String>>
格式的集合中,- 然后取出key为
EnableAutoConfiguration
的value值, - 这个value值内就是自动配置信息,
即自动配置类的全路径,自动配置类其实就是加了@Configuration和@Bean的配置类,用这个配置类代替了原本的xml配置,并且这些配置类都进行了默认配置,即"约定大于配置"
, - 有了自动配置类的全路径,spring就会找到这些配置类并加载到IOC容器中使配置生效。
所以整个过程就是各种spring-boot-stater的依赖,它们的jar包内提供好了自动配置类(使用java配置类的方式替代了xml配置),
但是springboot并不知道这些配置类的位置,也就无法将它们加载到IOC容器中让它们的配置生效。
所以每次加入spring-boot-stater的依赖就会将它们配置类的路径记录在spring.factories文件中,springboot需要做的就是去spring.factories文件中拿到这些配置类的路径,并根据路径找到配置类将它们加载进入IOC容器中,让它们的默认配置生效。