spring源码阅读(五)-Spring Import注解使用
说明
我们再读源码时常常发现这个注解,近期在读dubbo源码 就使用到了此注解,究竟有什么用,在spring boot项目中尤其多
Import的作用
实现将打了@Import的注解注入到容器,以及@Import指定的类注入到容器
import的三种使用方式
直接导入指定类的方式
1.定义一个打上了Import的类
/** * student和BeanRegisterConfig都会初始化进入容器 student的beanName为类的全名称 */ @Import({Student.class}) public class BeanRegisterConfig { }
2.main测试
public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(BeanRegisterConfig.class); //这里的参数代表要做操作的类 String [] names=applicationContext.getBeanDefinitionNames(); for (String name: names) { System.out.println(name); } }
3.输出
导入ImportSelector方式
允许我们自定义导入的类
1.定义一个ImportSelector类
public class BeanRegisterImportSelector implements ImportSelector { /** * * @param importingClassMetadata 注解元数据 * @return 返回值为要初始化的类的全名称 */ @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { for (String typeName : importingClassMetadata.getAnnotationTypes()) { System.out.println("typeName" + typeName); } //告诉容器初始化importtest.bean.Student return new String[]{"importtest.bean.Student"}; } }
2.定义一个打上了Import的类 导入BeanRegisterImportSelector
@Import({BeanRegisterImportSelector.class}) public class BeanRegisterConfig { }
3.测试
public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(BeanRegisterConfig.class); //这里的参数代表要做操作的类 String [] names=applicationContext.getBeanDefinitionNames(); for (String name: names) { System.out.println(name); } }
导入ImportBeanDefinitionRegistrar方式
ImportBeanDefinitionRegistrar 允许我们拿到BeanDefinitionRegistry 实现自定义注册
1.定义ImportBeanDefinitionRegistrar实现类
public class BeanRegisterImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * * @param importingClassMetadata 为@Import类的相关注解 * @param registry current bean definition registry */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { for (String typeName : importingClassMetadata.getAnnotationTypes()) { System.out.println("typeName" + typeName); } BeanDefinition beanDefinition=new RootBeanDefinition(); beanDefinition.setBeanClassName("importtest.bean.Student"); registry.registerBeanDefinition("student",beanDefinition); } }
2.定义import导入ImportBeanDefinitionRegistrar实现类
@Import({BeanRegisterImportBeanDefinitionRegistrar.class}) public class BeanRegisterConfig { }
3.main测试
public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(BeanRegisterConfig.class); //这里的参数代表要做操作的类 String [] names=applicationContext.getBeanDefinitionNames(); for (String name: names) { System.out.println(name); } }
例子通过Import实现自动化配置
1.定义配置文件canalClient.properties
canal.host=127.0.0.1
canal.port=9081
2.定义CanalClientInitConfig 配置
public class CanalClientInitConfig implements InitializingBean { @Value("${canal.host}") private String canalServerIp; @Value("${canal.port}") private String canalPort; /** * 利用spring生命周期 * @throws Exception */ @Override public void afterPropertiesSet() throws Exception { /** * 模拟自动监听 这里可以写自己的自动监听代码 */ System.out.println("开始监听host:"+canalServerIp+",port:"+canalPort); } }
3.定义ImportBeanDefinitionRegistrar实现类
public class CanalImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware { private Environment environment; @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //通过spring生命周期的InitializingBean 进行自动监听 //原RootBeanDefinition rootBeanDefinition=new RootBeanDefinition(CanalClientInitConfig.class); //参考优化后:https://www.cnblogs.com/LQBlog/p/12420860.html#autoid-4-2-0 //建造者模式,生成ServiceAnnotationBeanPostProcessor BeanDefinition的builder BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(CanalClientInitConfig.class); AbstractBeanDefinition rootBeanDefinition=builder.getBeanDefinition(); registry.registerBeanDefinition("canalClientInitConfig",rootBeanDefinition); } /** * Set the {@code Environment} that this component runs in. * * @param environment */ @Override public void setEnvironment(Environment environment) { this.environment=environment; } }
4.定义启动注解
@Target({ElementType.TYPE})//只能打在类上 @Retention(RetentionPolicy.RUNTIME)//保留到运行时 @Import(value = CanalImportBeanDefinitionRegistrar.class) @Inherited public @interface EnableCanalClient { }
5.启用canlaClient
@EnableCanalClient //spring注解方式 加载此路径的properties 到容器 @PropertySource("classpath:canalClient.properties") public class BeanRegisterConfig { }
6.man测试
public class CanalClientMain { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(BeanRegisterConfig.class); //这里的参数代表要做操作的类 String [] names=applicationContext.getBeanDefinitionNames(); for (String name: names) { System.out.println(name); } } }
7.输出
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!