您的位置:首页 > 编程语言 > Java开发

SpringBoot系列:自动配置源码分析

2019-04-01 20:52 911 查看

源码分析

@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());
}
}

总结:

  1. @SpringBootConfiguration将启动类标注为一个组件
  2. @EnableAutoConfiguration开启了自动配置功能
    其中:
    2.1 @AutoConfigurationPackage是扫描启动类的包及其子包的组件,进行自动配置
    2.2 @import(EnableAutoConfigurationImportSelector.class)是按照功能场景的需求添加springboot自身的组件,进行自动配置
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: