Spring @Import导入Bean的三种类型:Component、ImportSelector、ImportBeanDefinitionRegistrar

我们通过@Import注解的注释可以知道,我们可以在被Component标记的类下导入其他的类和实现ImportSelectorImportBeanDefinitionRegistrar接口的类

image-20220212212142514


1.在Component标记的类下导入第三方的类

我们知道@Import注解最最要的作用是用来批量导入第三方Jar包里面的类,因为第三方Jar包,并没有我们被我们Spring的注解所标记,对于少数的类我们可以通过@Bean注解导入IOC容器,想要批量导入时就可以用@Import注解

栗子:

@Configuration
@Import({Apple.class,Orange.class, Banana.class})
public class myConfig {

}

测试一下:

@Test
public void test(){
    ApplicationContext context = context = new AnnotationConfigApplicationContext(myConfig.class);
    String[] beanDefinitionNames = context.getBeanDefinitionNames();
    Arrays.asList(beanDefinitionNames).forEach(System.out::println);
}

打印结果:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
myConfig
com.fx.pojo.Apple
com.fx.pojo.Orange
com.fx.pojo.Banana

从这里我们可以看到通过@Import注入的类如果通过类名获取需要通过类的全路径名称获取,否者会报错


2. 注入实现了ImportSelector接口的类

有的时候我们有这样的业务需求:需要按照操作系统的类型来导入不同的类,例如在Windows系统下导入Apple类,在Linux系统下导入Banana类

ImportSelector字面上的意思就是导入选择器,根据条件导入不同的类。

怎么让不同的类可以通过同一个类名或者类的字节码文件获得呢?我们可以定义一个接口让我们想要分类的类实现这个接口,再利用多态进行转换

栗子:

定义一个接口:

public interface Fruit {}

让我们想要选择的类实现这个接口:

public class Apple implements Fruit{}
public class Banana implements Fruit{}

写一个类实现ImportSelector接口,并实现里面选择的方法selectImports

public class FruitImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //importingClassMetadata里面保存调用此选择器的类
        System.out.println("在PearImportSelector中"+importingClassMetadata.toString());
        //拿到操作系统名称
        String osName = System.getProperty("os.name");
        if(osName.contains("Windows")){
            //返回Apple类
            return new String[]{Apple.class.getName()};
        }else if(osName.contains("Linux")){
            //返回Banana类
            return new String[]{Banana.class.getName()};
        }
        return null;
    }
}

这时候我们要解析类中要导入的就是选择器类了

@Configuration
@Import({FruitImportSelector.class})
public class myConfig {}

测试一下,输出的是:

com.fx.pojo.Apple

当然我们可以通过注入这两个类的接口类获得具体的类

@Test
public void test(){
    ApplicationContext context = context = new AnnotationConfigApplicationContext(myConfig.class);
    String name = context.getBean(Fruit.class).getClass().getName();
    System.out.println(name);
}

输出:

com.fx.pojo.Apple

3. 注入实现了ImportBeanDefinitionRegistrar接口的类

可以看到通过@Import注入的类如果我们要通过类的全路径名才能从IOC容器拿到类的实例,这样比较麻烦,所以ImportBeanDefinitionRegistrar接口正是用来给类其别名,简化IOC容器中类的名称的

栗子:

先定义一个类实现下ImportBeanDefinitionRegistrar接口

public class FruitNameImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        //判断下Apple类是否在容器类了,beanDefinitionRegistry保存了IOC容器中所有Bean的定义项
        boolean flag = beanDefinitionRegistry.containsBeanDefinition("com.fx.pojo.Apple");
        if(flag){
            //先拿到bean的定义项,在Spring容器中每个Bean都被包装成了一个RootBeanDefinition
            RootBeanDefinition r = new RootBeanDefinition(Apple.class);
            //将类的访问名字从容器中修改一下
            beanDefinitionRegistry.registerBeanDefinition("Apple",r);
        }
    }
}

注入一下这个类:

@Configuration
@Import({Apple.class,FruitNameImportBeanDefinitionRegistrar.class})
public class myConfig {}

测试:

@Test
public void test(){
    ApplicationContext context = context = new AnnotationConfigApplicationContext(myConfig.class);
    String[] beanDefinitionNames = context.getBeanDefinitionNames();
    Arrays.asList(beanDefinitionNames).forEach(System.out::println);
}

打印结果:

Apple

通过这种方式就可以修改通过获得Bean实例的名字了

通过这种方式就可以修改通过获得Bean实例的名字了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值