spring boot大大简化了spring里面的各种配置,那么它是如何自动加载各种配置的呢?通过源码分析
springboot项目都有一个主启动类,主启动类最重要的注解是@SpringBootApplication
,@SpringBootApplication
又是由一系列注解组成的,大概的继承关系如下:
1 2 3 4 5 6 7 8 9 10 11 @SpringBootApplication : @EnableAutoConfiguration : @AutoConfigurationPackage @Import (AutoConfigurationImportSelector.class) …… ……
自动配置的核心功能又这两个注解完成:@AutoConfigurationPackage
和@Import(AutoConfigurationImportSelector.class)
。
@AutoConfigurationPackage @AutoConfigurationPackage的内容如下:
1 2 3 4 5 6 7 8 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage { }
1 2 3 4 5 6 7 8 9 10 11 12 13 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.Registrar类中的registerBeanDefinitions(),功能是注册一个Bean的定义。**new PackageImport(metadata).getPackageName()**,返回了当前主程序类的 同级以及子级 的包组件。也就是main文件所在文件夹包及其下面所有的包。当程序进行ioc注入的时候,只会注入这些包下面被@Bean
标注的对象。
@Import(AutoConfigurationImportSelector.class) AutoConfigurationImportSelector.class的源码如下,其中getAutoConfigurationEntry()方法实现了所有需要自动配置的类。
1 2 3 4 5 6 7 8 9 10 11 @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this .beanClassLoader); AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); }
getCandidateConfigurations()方法得到所有需要配置的候选类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 protected AutoConfigurationEntry getAutoConfigurationEntry (AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata); List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); }
其中加载配置在函数getCandidateConfigurations();
中,源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 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; } public static List<String> loadFactoryNames (Class<?> factoryType, @Nullable ClassLoader classLoader) { String factoryTypeName = factoryType.getName(); return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, 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 { Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories" ) : ClassLoader.getSystemResources("META-INF/spring.factories" ); LinkedMultiValueMap result = new LinkedMultiValueMap(); ……
SpringFactoriesLoader是Spring的一个工具类,功能是从指定的位置加载配置文件。因此,