1. 1@Import源码解析入口
ConfigurationClassParser.java
parse(){
processConfigurationClass()
// 处理selectImport 类,这里面自动装配的东西
this.deferredImportSelectorHandler.process();
}
ConfigurationClassParser.java
//开始循环解析包含指定注解的集合对象中的数据
public void parse(Set<BeanDefinitionHolder> configCandidates) {
// 循环遍历configCandidates
for (BeanDefinitionHolder holder : configCandidates) {
// 获取BeanDefinition
BeanDefinition bd = holder.getBeanDefinition();
// 根据BeanDefinition类型的不同,调用parse不同的重载方法,实际上最终都是调用processConfigurationClass()方法
try {
// 注解类型
if (bd instanceof AnnotatedBeanDefinition) {
// 注意,调用同名方法parse()->processConfigurationClass()->doProcessConfigurationClass(位置一)
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
// 有class对象的 。抽象类
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
//上面的parse,只是解析Componet等属性,
// 对于@Import的解析,普通的对象,直接进bd放到configurationClasses中,this.reader.loadBeanDefinitions(configClasses);
// 对于实现ImportSelector接口的,放到deferredImportSelectorHandler列表中,此处开始回到处理了。
// 获取所有的配置,遍历,调用处理import注解的方法,如果是普通的类,直接放进configurationClasses(键是对应上面configClasses)中
//此处开始处理handler中的class ,加载springboot中的自动装配的配置
this.deferredImportSelectorHandler.process();
}
接上面位置一处。
processConfigurationClass(){
//开始解析各种注解。里面有@Component注解等,启动注意@Import注解
//位置二
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
// 把解析到的结果保存起来。注意:如果Import是普通类,那么这里能保存上
this.configurationClasses.put(configClass, configClass);
}
1.2 解析@Import注解
承接上面的位置二
doProcessConfigurationClass{
// 处理 @Import注解。查找所有的@import注解,找到注解中的类并实例化。直接处理或者加入handler中
processImports(configClass, sourceClass, getImports(sourceClass), filter, true)
;
}
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
// 如果使用@Import注解修饰的类集合为空,那么直接返回
if (importCandidates.isEmpty()) {
return;
}
....
try {
// 遍历每一个@Import注解的类
for (SourceClass candidate : importCandidates) {
// 检验配置类Import引入的类是否是ImportSelector子类
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
// 候选类是一个导入选择器->委托来确定是否进行导入
Class<?> candidateClass = candidate.loadClass();
// 通过反射生成一个ImportSelect对象
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
// 获取选择器的额外过滤器
Predicate<String> selectorFilter = selector.getExclusionFilter();
if (selectorFilter != null) {
exclusionFilter = exclusionFilter.or(selectorFilter);
}
// 判断引用选择器是否是DeferredImportSelector接口的实例
// 如果是则应用选择器将会在所有的配置类都加载完毕后加载
if (selector instanceof DeferredImportSelector) {
// 重点核心-用来实现自动装配。。。。。将选择器添加到deferredImportSelectorHandler实例中,预留到所有的配置类加载完成后统一处理自动化配置类
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
// 获取引入的类,然后使用递归方式将这些类中同样添加了@Import注解引用的类
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
// 重点。递归处理。被Import进来的类也有可能@Import注解
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
// 如果是实现了ImportBeanDefinitionRegistrar接口的bd
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
// 候选类是ImportBeanDefinitionRegistrar -> 委托给当前注册器注册其他bean
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
/** * 放到当前configClass的importBeanDefinitionRegistrars中;在ConfigurationClassPostProcessor处理configClass时会随之一起处理 */
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
//说明仅仅是一个普通的类,还是解析它,其实里面什么都没处理,但是把它加入到configurationClasses中了,然后加载bd就有了
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
}
}
....
}
}
其中SpringBoot
中的自动装配类AutoConfigurationImportSelector implements DeferredImportSelector
,就是实现了DeferredImportSelector
接口。
经过上面的步骤,说有的@Import
标记的处理完成。
=》 // 回调,处理@Import 放进去的选择器 ,SpringBoot的自动装配
this.deferredImportSelectorHandler.process();
->handler.processGroupImports();
--> // 理解的重点
// getImports 获取到所有要装备的类,然后再遍历处理**
grouping.getImports().forEach{
//循环遍历,再调用自动装备的类,可能自动装配的类还有@Import注解
// 更为重要的是,解析该类的时候,如果是普通类,那么调用processConfigurationClass处理一遍,最后把
// bean信息放到this.configurationClasses.put(configClass, configClass);中去了。那么接下来就能放到容器的bdMaps中,等待实例化
processImports(...)
}
--->
public Iterable<Group.Entry> getImports() {
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
//调用process 方法了,这里过度到SpringBoot
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getImportSelector());
}
return this.group.selectImports();
}
==============================到SpringBoot===============================
AutoConfigurationImportSelector#process(){
->getAutoConfigurationEntry(..)
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
//获取所有的自动装配的配置。本例获取到130个
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
//排除掉不符合条件的
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
//本例还有34个
return new AutoConfigurationEntry(configurations, exclusions);
}
获取到到配置文件中的配置
2. @Import为什么需要用@Component或衍生注解标记
2.1 xml
加上@Component
注解,
public class TestSelfTag {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user=(User)context.getBean("user");
}
}
<context:component-scan base-package="com.songbl.selftag" >
</context:component-scan>
@Component
@Import(User.class)
public class MyImportTestBean {
}
xml形式启动的时候,加上这个注解,才能doScan 扫描进去,放bdMaps中。
在ConfigurationClassPostProcessor 解析的时候,获取所有的已经注册的bd
String[] candidateNames = registry.getBeanDefinitionNames();
,如果不加这个注解,那么没放进去,
获取不到,就没法解析了,@Import就不生效了。
2.1 注解
public static void main(String[] args) throws NoSuchMethodException {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
//注册bd到容器
ac.register(MyTestConfiguration.class);
ac.refresh();
}
@Component
@ComponentScan(basePackages="com.songbl.selftag")
public class MyTestConfiguration { }
对于注解启动的,调用register方法注册了bean信息,后面获取的时候,
//获得上面注册MyTestConfiguration的bd
String[] candidateNames = registry.getBeanDefinitionNames();
if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
// 添加到对应的集合对象中(带注解的放进去);本例MyTestConfiguration 被@ComponentScan(basePackages="com.songbl.selftag")
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
// 然后parse(上面准备的列表configCandidates),递归处理,本例到这里开始处理@ComponentScan(basePackages="com.songbl.selftag")了
总结:想让生效,就要用@Component 或者衍生注解 标记,使得扫描进去,才有机会被处理