个人博客:槿苏的知识铺
一、什么是自动装配
SpringBoot
定义了一套接口规范,这套规范规定:SpringBoot
在启动时会扫描外部引用jar包中的META-INF/spring.factories
文件,将文件中配置的类型信息加载到Spring
容器,并执行类中定义的各种操作。对于外部jar包来说,只需要按照SpringBoot
定义的标准,就能将自己的功能装配到SpringBoot
中。
二、自动装配的实现原理
自动装配的实现,离不开SpringBootApplication
这个核心注解。查看这个注解的源码,我们会发现在SpringBootApplication
注解上,存在着几个注解,其中SpringBootConfiguration
、EnableAutoConfiguration
、ComponentScan
这三个注解是需要我们注意的。
@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication {...}
(1) ComponentScan
扫描被
@Component 、@Service
注解的bean,该注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean。如SpringBootApplication
注解源码所示,容器中将排除TypeExcludeFilterh和AutoConfigurationExcludeFilter。
(2) EnableAutoConfiguration
启用 SpringBoot 的自动配置机制
(3) Configuration
允许在上下文中注册额外的 bean 或导入其他配置类
2.1 EnableAutoConfiguration详解
@EnableAutoConfiguration是实现自动装配的重要注解,在这个注解上存在以下两个注解:AutoConfigurationPackage
、Import
。
@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration {...}
2.1.1 AutoConfigurationPackage
表示对于标注该注解的类的包,应当使用
AutoConfigurationPackages
注册。实质上,它负责保存标注相关注解的类的所在包路径。使用一个BasePackage类,保存这个路径。然后使用@Import注解将其注入到ioc容器中。这样,可以在容器中拿到该路径。
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {register(registry, new PackageImport(metadata).getPackageName());}}
查看
AutoConfigurationPackages
中的Registrar
这个类的源码,在Registrar#registerBeanDefinitions
方法中有这样一句代码new PackageImport(metadata).getPackageName()
,查看PackageImport的构造器后不难发现,这里获取的是StandardAnnotationMetadata
这个实例所在的包名。
/** * metadata: 实际上是 StandardAnnotationMetadata 实例。 * metadata#getClassName(): 获取标注 @AutoConfigurationPackage 注解的类的全限定名。 * ClassUtils.getPackageName(…): 获取其所在包。 */PackageImport(AnnotationMetadata metadata) {this.packageName = ClassUtils.getPackageName(metadata.getClassName());}
此时再回去看
Registrar#registerBeanDefinitions
中调用的AutoConfigurationPackages#register
方法
public static void register(BeanDefinitionRegistry registry, String... packageNames) {// BEAN:AutoConfigurationPackages类的全限定名// 此时判断BeanDefinitionRegistry中是否存在以BEAN作为beanName的BeanDefinition对象// 如果不存在,走else方法,构造了一个BackPackages实例,进行注册if (registry.containsBeanDefinition(BEAN)) {BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();constructorArguments.addIndexedArgumentValue(0,addBasePackages(constructorArguments, packageNames));} else {GenericBeanDefinition beanDefinition = new GenericBeanDefinition();beanDefinition.setBeanClass(BasePackages.class);beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);registry.registerBeanDefinition(BEAN, beanDefinition);}}
2.1.2 Import(AutoConfigurationImportSelector.class)
它是利用
AutoConfigurationImportSelector
机制再来给容器中批量导入一些配置东西的,接下来带大家了解究竟导入了哪些内容。
/** * AutoConfigurationImportSelector类中存在一个叫selectImports的方法,就是我们到底要向容器中导入哪些 * 内容,都会在这里进行扫描并导入。 */@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) { // 判断EnableAutoConfiguration是否开启默认开启true if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } // 1.加载META-INF/spring-autoconfigure-metadata.properties 文件 // 2.从中获取所有符合条件的支持自动装配的类 // 自动配置类全名.条件=条件的值 AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader); // 获取AutoConfigurationEntry AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}
接下来重点看
getAutoConfigurationEntry(annotationMetadata)
方法,利用这个方法向容器中批量导入一些默认支持自动配置的类,当你理解了这部分内容之后,就基本了解了Spring Boot是如何进行自动装配的,废话不多说,让我们进入正题。
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { // 判断EnableAutoConfiguration是否开启默认开启true if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } // 获取注解属性 AnnotationAttributes attributes = getAttributes(annotationMetadata); // 调用getCandidateConfigurations(annotationMetadata, attributes),利用loadSpringFactories(ClassLoader classLoader)加载当前系统所有的META-INF/spring.factories文件,得到默认支持的自动配置的类的列表 List configurations = getCandidateConfigurations(annotationMetadata, attributes); // 去除重复的 configuration configurations = removeDuplicates(configurations); // 获取到SpringBootApplication上exclude和excludeName配置的需要排除的类 Set exclusions = getExclusions(annotationMetadata, attributes); // 检查configurations是否含有exclusions中的类 checkExcludedClasses(configurations, exclusions); // 将exclusions中的类从configurations中排除 configurations.removeAll(exclusions); // 对所有候选的自动配置类进行筛选, // 比如ConditionalOnProperty 当属性存在时 // ConditionalOnClass 当class存在 // ConditionalOnMissingClass 当这个clas不存在时才去配置 // 过滤器 configurations = getConfigurationClassFilter().filter(configurations); // 将自动配置的类,导入事件监听器,并触发fireAutoConfigurationImportEvents事件// 加载META-INF\spring.factories中的AutoConfigurationImportListener fireAutoConfigurationImportEvents(configurations, exclusions); // 创建AutoConfigurationEntry对象 return new AutoConfigurationEntry(configurations, exclusions);}