springboot自动装配原理
-
springboot的自动装配由注解
@SpringBootApplication
实现@SpringBootApplication: @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
此注解的实现如下,主要关注
@SpringBootConfiguration
,@EnableAutoConfiguration
和@ComponentScan
三个注解 -
@SpringBootConfiguration
标注某一个类被当作一个springboot的配置类,可以看到它地层中有一个@configuration
,将被作为一个组件加载到spring容器中
@SpringBootConfiguration:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
@EnableAutoConfiguration
主要用来实现自动配置功能
@EnableAutoConfiguration:
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
此处需要关注@AutoConfigurationPackage
和@Import(AutoConfigurationImportSelector.class)
-
@AutoConfigurationPackage
将 添加该注解的类所在的package 作为 自动配置package 进行管理,底层如下。@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(AutoConfigurationPackages.Registrar.class)
它会导入
AutoConfigurationPackages.Registrar.class
。static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0])); } @Override public Set<Object> determineImports(AnnotationMetadata metadata) { return Collections.singleton(new PackageImports(metadata)); } }
这个方法会获取到启动类所在的包的包名,然后将其中的所有package设置为自动装配。
-
AutoConfigurationImportSelector.class
中加载了一些环境,并获取到了配置列表,此类为自动导入配置的核心AutoConfigurationImportSelector.class List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); //此方法从META-INF/spring.factories中把所有的配置文件加载到容器中 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()
中会调用以下两个函数loadSpringFactories()
,loadSpringFactories()
会遍历所有的配置文件,将它们的配置文件从FACTORIES_RESOURCE_LOCATION
中加载资源,这个值就是先前的配置文件路径。public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { ClassLoader classLoaderToUse = classLoader; if (classLoaderToUse == null) { classLoaderToUse = SpringFactoriesLoader.class.getClassLoader(); } String factoryTypeName = factoryType.getName(); return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList()); } private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) { Map<String, List<String>> result = cache.get(classLoader); if (result != null) { return result; } result = new HashMap<>(); try { Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION); while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry<?, ?> entry : properties.entrySet()) { String factoryTypeName = ((String) entry.getKey()).trim(); String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String) entry.getValue()); for (String factoryImplementationName : factoryImplementationNames) { result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>()) .add(factoryImplementationName.trim()); } } } // Replace all lists with unmodifiable lists containing unique elements result.replaceAll((factoryType, implementations) -> implementations.stream().distinct() .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList))); cache.put(classLoader, result); } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } return result; }
在getCandidateConfigurations()
中,获取到的是EnableAutoConfiguration.class
,即将标有@EnableAutoConfiguration
注解的类所需要的配置文件自动装配。即上一步获取的所有配置文件都被装配了。
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
而在配置文件中存在存在@ConditionalOnXXX
的注解,意思是只有满足某些条件时,这些配置文件才会生效。
总结:springboot 自动配置的核心是@EnableAutoConfiguration
,这个注解的底层有两个地方需要注意,分别为@Import(AutoConfigurationImportSelector.class)
和@AutoConfigurationPackage
。AutoConfigurationImportSelector.class
的作用是加载所有的配置文件,它会把所有的配置文件从META-INF/spring.factories
路径下加载到一个properties文件中,并且为带有@EnableAutoConfiguration
的类自动配置。而配置文件中有@ConditionalOnXXX
类的注解,因此只有安装的starter,配置文件才会生效。
@AutoConfigurationPackage
会首先获取到启动类所在包的包名,然后将启动类所在的package中所有的package作为自动配置package。这样所有的package中所有的需要配置的启动器都会被自动配置。