从@Import的源码解读Springboot的自动装配
创始人
2025-05-28 21:30:23
0

1. 1@Import源码解析入口

ConfigurationClassParser.java
parse(){
processConfigurationClass()

// 处理selectImport 类,这里面自动装配的东西
this.deferredImportSelectorHandler.process();
}

ConfigurationClassParser.java
//开始循环解析包含指定注解的集合对象中的数据public void parse(Set configCandidates) {// 循环遍历configCandidatesfor (BeanDefinitionHolder holder : configCandidates) {// 获取BeanDefinitionBeanDefinition 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 importCandidates, Predicate 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 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 importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);// 重点。递归处理。被Import进来的类也有可能@Import注解processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);}}// 如果是实现了ImportBeanDefinitionRegistrar接口的bdelse  if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {// Candidate class is an ImportBeanDefinitionRegistrar ->// delegate to it to register additional bean definitions// 候选类是ImportBeanDefinitionRegistrar  -> 委托给当前注册器注册其他beanClass 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 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 configurations = getCandidateConfigurations(annotationMetadata, attributes);configurations = removeDuplicates(configurations);Set 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");}
}
 
@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的bdString[] 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 或者衍生注解 标记,使得扫描进去,才有机会被处理

相关内容

热门资讯

章程修正案 章程修正案  公司创建后,根据公司发展的需要而修改公司章程,而章程修正案就是对公司章程的修改内容由公...
人力资源公司运营的管理方案 人力资源公司运营的管理方案(通用10篇)  为了确保工作或事情能有条不紊地开展,就需要我们事先制定方...
社区工作者事迹 社区工作者事迹青春在平凡的岗位上闪光小时候经常看到戴着红袖章,提着土广播走街串巷的婆婆妈妈们,她们是...
文秘工作内容 文秘工作内容  文秘分为行政文员、办公室文员、秘书等,不同的职业也不同的工作内容,本文主要为您介绍有...
网络安全教育方案 网络安全教育方案(精选9篇)  为保障事情或工作顺利开展,常常需要提前进行细致的方案准备工作,方案是...
XX公司人事管理制度(2) XX公司人事管理制度(2)pan> 关键词: 评论 文章“XX公司人事管理制度(2)” 1、...
公司应急值班管理制度 公司应急值班管理制度(精选10篇)  在社会发展不断提速的今天,人们运用到制度的场合不断增多,制度一...
通知的格式、写法 通知的格式、写法通知是一种使用范围较广的文体。凡需要特定机关和人员知道、办理的事宜,都可以用通知。但...
陕西省建筑职工大学分类考试招... 陕西省建筑职工大学2016年分类考试招生章程  根据国家教育部和陕西省教育厅有关规定,陕西省建筑职工...
大学生寒假就业实践报告 大学生寒假就业实践报告(精选25篇)  转眼难忘的社会实践生活就已结束了,这段经历,相信你有很多感悟...
责任状 责任状范本  责任状作为一种公共管理手段,上下级就某项工作签订责任状,上级将工作任务布置给下级,下级...
工地施工现场管理制度 工地施工现场管理制度(精选17篇)  在当今社会生活中,大家逐渐认识到制度的重要性,制度一经制定颁布...
创意提案改善制度 创意提案改善制度□ 目 的 ?第一条 为启发全体员工的想像力,集结个人的智慧与经验,提出有利于本公司...
工会财务管理制度 工会财务管理制度范本  在生活中,很多地方都会使用到制度,制度是各种行政法规、章程、制度、公约的总称...
文明的倡议书 关于文明的倡议书15篇  在日常生活和工作中,接触并使用倡议书的人越来越多,倡议书是一种号召性的专用...
生产管理制度 生产管理制度(精选18篇)  制度指一定的规格或法令礼俗。用社会科学的角度来理解,制度泛指以规则或运...
计算机软件管理制度 计算机软件管理制度  在当今社会生活中,很多地方都会使用到制度,制度具有合理性和合法性分配功能。那么...
学校学生考勤的管理制度 学校学生考勤的管理制度(通用5篇)  在快速变化和不断变革的今天,越来越多地方需要用到制度,制度一经...
厨房管理规章制度 厨房管理规章制度  在日新月异的现代社会中,制度使用的情况越来越多,制度是各种行政法规、章程、制度、...
监控录像管理制度 关于监控录像管理制度(通用13篇)  在现在的社会生活中,越来越多人会去使用制度,制度是指在特定社会...