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

 

posted @ 2021-10-15 11:50  意犹未尽  阅读(237)  评论(0编辑  收藏  举报