自动配置
Spring Boot应用的启动入口是@SpringBootApplication注解标注类中的main()方法,
@SpringBootApplication能够扫描Spring组件并自动配置Spring Boot
- 查看**@SpringBootApplication**内部源码进行分析
@SpringBootApplication注解是一个组合注解,前面 4 个是注解的元数据信息, 我们主要看后面三个核心注解:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
@Target({ElementType.TYPE}) //注解的适用范围,Type表示注解可以描述在类、接口、注解或枚举中
@Retention(RetentionPolicy.RUNTIME) //表示注解的生命周期,Runtime运行时
@Documented //表示注解可以记录在javadoc中
@Inherited //表示可以被子类继承该注解
@SpringBootConfiguration // 标明该类为配置类
@EnableAutoConfiguration // 启动自动配置功能
@ComponentScan( // 包扫描器
excludeFilters = {@Filter( type =FilterType.CUSTOM, classes ={TypeExcludeFilter.class} ), @Filter( type =FilterType.CUSTOM, classes ={AutoConfigurationExcludeFilter.class} )})
public @interface SpringBootApplication { ... }
- @SpringBootConfiguration注解
@SpringBootConfiguration注解表示Spring Boot配置类。查看@SpringBootConfiguration注解源
码,核心代码具体如下:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented @Configuration //配置IOC容器
public @interface SpringBootConfiguration
{ }
从上述源码可以看出,@SpringBootConfiguration注解内部有一个核心注解@Configuration,该
注解是Spring框架提供的,表示当前类为一个配置类(XML配置文件的注解表现形式),并可以被组件
扫描器扫描。由此可见,@SpringBootConfiguration注解的作用与@Configuration注解相同,都是标
识一个可以被组件扫描器扫描的配置类,只不过@SpringBootConfiguration是被Spring Boot进行了重
新封装命名而已
- @EnableAutoConfiguration注解
@EnableAutoConfiguration注解表示开启自动配置功能,该注解是Spring Boot框架最重要的注解,也是实现自动化配置的注解。
它是一个组合注解,Spring 中有很多以Enable开头的注解,其作用就是借助@Import来收集并注册特定场景相关的bean,并加载到IoC容器。@EnableAutoConfiguration就是借助@Import来收集所有符合自动配置条件的bean定义,并加载到IoC容器。主要有两个核心注解:@AutoConfigurationPackage,@Import({AutoConfigurationImportSelector.class})
- @AutoConfigurationPackage注解
源码分析:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class}) // 导入Registrar中注册的组件
public @interface AutoConfigurationPackage { }
从上述源码可以看出,@AutoConfigurationPackage注解的功能是由@Import注解实现的,它是spring框架的底层注解,它的作用就是给容器中导入某个组件类,例如@Import(AutoConfigurationPackages.Registrar.class),它就是将Registrar这个组件类导入到容器中,可查看Registrar类中registerBeanDefinitions方法,这个方法就是导入组件类的具体实现 :
从上述源码可以看出,在Registrar类中有一个registerBeanDefinitions()方法,@AutoConfigurationPackage注解的主要作用就是将主程序类所在包及所有子包下的组件到扫描到spring容器中。
- @Import({AutoConfigurationImportSelector.class})
@Import将AutoConfigurationImportSelector这个类导入到spring容器中,AutoConfigurationImportSelector可以帮助springboot应用将所有符合条件的@Configuration配置
都加载到当前SpringBoot创建并使用的IoC容器(ApplicationContext)中
AutoConfigurationImportSelector 通过源码分析这个类中是通过selectImports这个方法导入需要的组件。
loadMetadata方法
getCandidateConfigurations方法,有一个重要方法oadFactoryNames,这个方法是让SpringFactoryLoader去加载一些组件的名字
loadFactory方法
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader)
{
//获取出入的键 String factoryClassName = factoryClass.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); }
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader)
{ MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null)
{ return result; }
else {
try {
//如果类加载器不为null,则加载类路径下spring.factories文件,将其中设置 的配置类的全路径信息封装 为Enumeration类对象 Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories"); LinkedMultiValueMap result = new LinkedMultiValueMap();
//循环Enumeration类对象,根据相应的节点信息生成Properties对象,通过传入 的键获取值,在将值切割为一个个小的字符串转化为Array,方法result集合中
while(urls.hasMoreElements())
{
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
String factoryClassName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11)
{
String factoryName = var9[var11]; result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
最后就是获取META- INF下spring.factories文件
@EnableAutoConfiguration就是从classpath中搜寻META-INF/spring.factories配置文件,并将其中
org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项通过反射(Java
Refletion)实例化为对应的标注了@Configuration的JavaConfig形式的配置类,并加载到IOC容器中
- @ComponentScan注解
@ComponentScan注解具体扫描的包的根路径由Spring Boot项目主程序启动类所在包位置决定,在扫描过程中由前面介绍的**@AutoConfigurationPackage**注解进行解析,从而得到Spring Boot项目主程序启动类所在包的具体位置。
总结一下
- @SpringBootApplication 的注解的功能, 简单来说就是 3 个注解的组合注解:
|- @SpringBootConfiguration
|- @Configuration //通过javaConfig的方式来添加组件到IOC容器中
|- @EnableAutoConfiguration
|- @AutoConfigurationPackage //自动配置包,与@ComponentScan扫描到的添加到IOC
|- @Import(AutoConfigurationImportSelector.class) //到META- INF/spring.factories中定义的bean添加到IOC容器中 |- @ComponentScan //包扫描
springboot底层实现自动配置的执行流程步骤:
- springboot应用启动;
- @SpringBootApplication起作用;
- @EnableAutoConfiguration;
- @AutoConfigurationPackage:这个组合注解主要是
@Import(AutoConfigurationPackages.Registrar.class),它通过将Registrar类导入到容器中,而
Registrar类作用是扫描主配置类同级目录以及子包,并将相应的组件导入到springboot创建管理
的容器中; - @Import(AutoConfigurationImportSelector.class):它通过将
AutoConfigurationImportSelector类导入到容器中,AutoConfigurationImportSelector类作用
是通过selectImports方法执行的过程中,会使用内部工具类SpringFactoriesLoader,查找
classpath上所有jar包中的META-INF/spring.factories进行加载,实现将配置类信息交给
SpringFactory加载器进行一系列的容器创建过程