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 {}
@SpringBootConfiguration
由springboot定义,标注一个springboot配置类,配置类相当于配置文件,是容器中的一个组件.
而@SpringBootConfiguration的注解@Configuration是由spring定义.
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration {}
@EnableAutoConfiguration
开启自动配置功能
被@AutoConfigurationPackage(自动配置包)标注,
被@import(EnableAutoConfigurationImportSelector.class)标注
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(EnableAutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {}
EnableAutoConfigurationImportSelector.class是决定导入哪些组件的选择器,父类AutoConfigurationImportSelector.class的public String[] selectImports(AnnotationMetadata annotationMetadata)方法将需要的组件以全类名的String[]的方式返回,添加到容器中,会给容器导入很多自动配置类(xxxAutoConfiguration,位于spring-boot-autoconfigure.jar),作用是导入这个功能场景需要的所有组件并配置好,免去了手动编写配置注入功能组件
@Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } try { AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader); AnnotationAttributes attributes = getAttributes(annotationMetadata); List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); configurations = sort(configurations, autoConfigurationMetadata); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return configurations.toArray(new String[configurations.size()]); } catch (IOException ex) { throw new IllegalStateException(ex); } }
得到这个String[]的方法是getCandidateConfigurations(annotationMetadata, attributes),内部调用SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()),
第一个参数getSpringFactoriesLoaderFactoryClass()即EnableAutoConfiguration.class.
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; }
loadFactoryNames方法
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); try { Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); List<String> result = new ArrayList<String>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url)); String factoryClassNames = properties.getProperty(factoryClassName); result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames))); } return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }
通过类加载器的getResources方法(参数为"META-INF/spring.factories")从类路径下的META-INF/spring.factories获取EnableAutoConfiguration指定的值,这些值作为自动配置类导入到容器中.
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
@AutoConfigurationPackage又被@import(spring的底层注解,给容器中导入一个组件,由括起的AutoConfigurationPackages.Registrar.class来决定导入的组件)标注.
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage {}
new PackageImport(metadata).getPackageName()所代表的即是被@SpringBootApplication标注的主配置类所在的包,意味着将及其子包内的所有组件都扫描到spring容器中.
@Order(Ordered.HIGHEST_PRECEDENCE) static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { @Override public void registerBeanDefinitions(AnnotationMetadata metadata,BeanDefinitionRegistry registry) { register(registry, new PackageImport(metadata).getPackageName()); } }
总结:
- @SpringBootConfiguration将启动类标注为一个组件
- @EnableAutoConfiguration开启了自动配置功能
其中:
2.1 @AutoConfigurationPackage是扫描启动类的包及其子包的组件,进行自动配置
2.2 @import(EnableAutoConfigurationImportSelector.class)是按照功能场景的需求添加springboot自身的组件,进行自动配置
- 通过实例及源码分析关于SpringBoot启动类启动时自动配置问题
- 【Spring Boot 系列 自动配置原理分析】
- SpringBoot——自动配置源码分析
- SpringBoot SpringApplication底层源码分析与自动装配
- SpringBoot-Loader源码分析系列2:启动 new JarLauncher().launch(args)的.launch(args)部分
- spring boot自动配置与启动流程分析
- SpringBoot-Loader源码分析系列1:启动&读取MANIFEST.MF文件
- SpringBoot源码分析之BeanDefinitionLoader注册主Configuration的Java配置类
- Spring boot实战中自动配置原理分析
- SpringBoot源码分析之环境和配置文件的加载
- 【Spring Boot】SpringBoot-自动配置源码解析
- springboot源码解析:自己实现一个springboot自动配置
- 超简单的springboot自动配置原理分析
- SpringBoot系列三:SpringBoot基本概念(统一父 pom 管理、SpringBoot 代码测试、启动注解分析、配置访问路径、使用内置对象、项目打包发布)
- SpringBoot自动配置原理分析
- Spring Developer Tools 源码分析:三、重启自动配置
- SpringBoot自动配置简单分析
- 通过Spring Boot整合Mybatis分析自动配置详解
- SpringBoot自动配置的简单分析
- Springboot系列:Springboot与Thymeleaf模板引擎整合基础教程(附源码)