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.输出