当前位置: 首页 > web >正文

@Import原理与实战

文章目录

  • 前言
  • 一、导入普通类
  • 二、导入ImportSelector实现类
  • 三、导入ImportBeanDefinitionRegistrar实现类
  • 四、@Import注解的解析
    • 4.1、解析实现ImportSelector的候选bean
    • 4.2、解析实现ImportBeanDefinitionRegistrar的候选bean
    • 4.3、DeferredImportSelector的特殊处理
  • 总结


前言

  @Import是Spring框架提供的一个核心注解,主要用于在配置类中引入其他配置类或组件。通过在类上标注@Import注解,可以将其value属性中指定的类注册到Spring容器中,从而实现配置的模块化和灵活组合。

一、导入普通类

  @Import注解会将其中导入的普通类,注册成bean放入到Spring容器中。

public class Demo1 {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);System.out.println(context.getBean(MyService.class));}
}class MyService {
}@Configuration
@Import(MyService.class) 
class Config {}

  运行结果:

com.itbaima.importdemo.demo1.MyService@55183b20

二、导入ImportSelector实现类

  解析@Import注解时会执行实现了ImportSelector的类的selectImports方法,将返回的数组中的类注册成bean。

public class Demo2 {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config1.class);System.out.println(context.getBean(MyService.class));}
}@Configuration
@Import(MyImport.class)
class Config1{}class MyImport implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[]{"com.itbaima.importdemo.demo1.MyService"};}
}

  运行结果

com.itbaima.importdemo.demo1.MyService@33d512c1

三、导入ImportBeanDefinitionRegistrar实现类

  实现了ImportBeanDefinitionRegistrar的类,可以自己注册bean定义,以及从已有的bean定义中获取指定的bean,进行修改,自由度是最高的。

public class Demo3 {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);System.out.println(context.getBean("orderService"));}
}@Configuration
@Import({MyBeanDefinitionRegistrar.class})
class Config {
}class MyBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) {GenericBeanDefinition bd = new GenericBeanDefinition();bd.setBeanClass(MyService.class);registry.registerBeanDefinition("orderService", bd);}
}class MyService {
}

  运行结果:

com.itbaima.importdemo.demo2.MyService@2f9f7dcf

四、@Import注解的解析

  @Import注解的解析,体现在refresh方法中的invokeBeanFactoryPostProcessors(调用所有bean工厂后置处理器)这一步:
在这里插入图片描述
  ConfigurationClassPostProcessor,用于配置类的解析:
在这里插入图片描述
  在org.springframework.context.annotation.ConfigurationClassParserprocessImports中完成对于@Import注解的解析:
在这里插入图片描述

4.1、解析实现ImportSelector的候选bean

  对于候选bean实现了ImportSelector接口的处理:

  1. 利用JVM的类加载机制,对于候选bean进行加载。
  2. 使用Spring提供的工具方法instantiateClass反射创建这个ImportSelector实例,并注入必要的环境参数。
  3. 如果候选bean实现了DeferredImportSelector,则将其加入deferredImportSelectors的集合中,延迟处理
  4. 候选bean实现的是ImportSelector接口,就调用目标类重写的selectImports方法,决定要导入哪些类名。然后把类名数组转换成 SourceClass 的集合,并应用排除过滤器。

在这里插入图片描述
  调用目标类重写的selectImports方法,传入的参数就是加入了@Configuration注解的配置类的元信息。最后一步递归调用processImports方法很关键:假设当前第一次调用processImports方法,解析出的类路径是com.itbaima.importdemo.demo1.MyService,那么在递归调用processImports方法时,再次进入
在这里插入图片描述
  循环中进行解析时,由于MyService没有实现ImportSelectorImportBeanDefinitionRegistrar注解,就会进入最后的else分支:(@Import导入的普通bean,进入的也是该分支)
在这里插入图片描述
  在最后的else分支中,还会去递归调用processConfigurationClass,将MyService当做配置类去解析,最终将解析完成的放入到ConfigurationClass的集合中。(注意,通过Import解析出的类路径下的bean,bean名称为空,后续需要再次进行处理。)
在这里插入图片描述
  this.reader.loadBeanDefinitions(configClasses);这一步,会对于@Import导入的普通bean进行处理:
在这里插入图片描述
  生成一个beanName,并且将bean定义注册到bean工厂中:
在这里插入图片描述

4.2、解析实现ImportBeanDefinitionRegistrar的候选bean

  @Import导入实现ImportBeanDefinitionRegistrar的候选bean的解析逻辑,在else…if的分支中,同样是通过JVM的类加载机制,加载候选类的class类,然后使用Spring提供的工具方法instantiateClass反射创建这个ImportBeanDefinitionRegistrar实例,并注入必要的环境参数。
在这里插入图片描述
  最后将其加入到ConfigurationClassimportBeanDefinitionRegistrars属性中:
在这里插入图片描述
  它的解析同样是在processConfigBeanDefinitionsthis.reader.loadBeanDefinitions(configClasses);中:
在这里插入图片描述
  回调用户重写的registerBeanDefinitions的逻辑。
在这里插入图片描述

4.3、DeferredImportSelector的特殊处理

  用户实现ImportSelector时,有一种特殊的情况,即用户实现了DeferredImportSelectorDeferredImportSelectorImportSelector的子类。在该分支中,仅仅是先将其加入DeferredImportSelectorHandlerdeferredImportSelectors属性中:
在这里插入图片描述
  DeferredImportSelectorHandlerdeferredImportSelectors属性是一个集合:
在这里插入图片描述
  最终会在所有bean解析完成后再去进行解析:
在这里插入图片描述
  该机制主要应用于Spring Boot的自动配置场景,其核心作用是确保用户自定义的Bean能够优先于自动配置的Bean执行。由于spring.factories中定义的自动配置Bean通常采用条件装配机制,当容器中已存在用户自定义的同类型Bean时,系统将不再重复装配。这正是通过@Bean注解添加的Bean能够覆盖默认Bean的原因
在这里插入图片描述
在这里插入图片描述
  在doProcessConfigurationClass中,默认的@Bean的注解,是后于@Import注解解析的。如果你不显式允许覆盖,Spring 在注册 BeanDefinition 时会抛出异常或者忽略重复的注册。
在这里插入图片描述
  但是对于DeferredImportSelector的解析,是在doProcessConfigurationClass的外层parse方法中执行的,后于@Bean注解的解析。

总结

  @Import注解是为了替换掉配置文件中的import标签,主要是为了导入第三方的配置类,除此之外:

  1. 可以在配置类中指定@Import注解,将其中的类注入到容器中。
  2. 可以在配置类中指定@Import注解,同时其中的类实现了Import Selector接口,会执行重写的selectImports方法,并且将其中指定的路径的对象注入到容器中。
  3. 如果导入的类型实现了Import BeanDefinitionRegistrar,则可以自己注册 BeanDefinition,自由度更高。

http://www.xdnf.cn/news/12977.html

相关文章:

  • VBA经典应用69例应用8:利用VBA,预设某个程序在晚上21点运行
  • 浮点数精度问题(CSP38思考)
  • (新)Gateway网关+基于Nacos配置动态路由
  • 【Ftrace专栏】function graph的trace输出格式使用
  • NumPy数组属性
  • 《最短路(Floyd)》题集
  • Qwen3开源最新Embedding模型
  • Cesium快速入门到精通系列教程八:时间系统
  • 【术语扫盲】评估指标Precision、Recall、F1-score、Support是什么含义?
  • 论文解析:一文弄懂Transformer!
  • Visio粘贴Word公式技巧
  • 深究二分查找算法:从普通到进阶
  • AI书签管理工具开发全记录(十六):Sun-Panel接口分析
  • Java中线程的常用方法
  • 6月8日python-AI代码
  • RPG23.应用武器伤害(一):设置武器命中
  • AD学习(2)
  • 深入理解链接与加载:从静态库到动态库的全流程解析
  • OD 算法题 B卷【反转每对括号间的子串】
  • Java设计模式面试题详解
  • 第十二讲 | 二叉搜索树
  • 庖丁解java(一篇文章学java)
  • 风控系统中常用的概念和架构学习
  • golang循环变量捕获问题​​
  • Ⅱ.楔子 -- C♭和 cbc
  • 经典算法:排序链表
  • DQN算法(详细注释版)
  • 开源项目实战学习之YOLO11:12.7 ultralytics-models-transformer.py
  • SpringMVC简介
  • 【GPT模型训练】第一课:安装PyTorch环境