@Import的三种用法演示

175 阅读2分钟

掌握@Import的用法是我们阅读spring源码的必要条件,以下做一个总结

  • 直接填class数组方式
  • ImportSelector方式
  • ImportBeanDefinitionRegistrar方式

1)直接填class数组的方式

/**
 * description:
 * 测试@import的用法,同时引入两个bean
 * 直接填class数组方式
 * author:dingyawu
 * date:created in 23:37 2020/12/4
 * history:
 */
@Configuration
@Import({Person.class, Employee.class})
public class PersonConfig8 {
}

测试demo

@Test
public void testImport() {
  ApplicationContext ac = new AnnotationConfigApplicationContext(PersonConfig8.class);
  String[] names = ac.getBeanDefinitionNames();
  Arrays.stream(names).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
personConfig8
com.roy.beans.Person
com.roy.beans.Employee
  1. ImportSelector的方式 ImportSelector的实现类
public class MyImportSelector implements ImportSelector {
    /**
     * 返回值为需要导入到容器中的bean的全类名数组
     * AnnotationMetadata:当前标注@Import注解的类的所有注解信息
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{Person.class.getName(), Employee.class.getName()};
    }
}

配置类

@Configuration
@Import({User.class, MyImportSelector.class})
public class PersonConfig9 {
}

测试demo 证明容器中是有Person和Employee两个bean的

/** 测试MyImportSelectord的用法,可以一次性注入好多bean */
@Test
public void testMyImportSelector() {
  ApplicationContext ac = new AnnotationConfigApplicationContext(PersonConfig9.class);
  String[] names = ac.getBeanDefinitionNames();
  Arrays.stream(names).forEach(System.out::println);
}

3) ImportBeanDefinitionRegistrar方式

ImportBeanDefinitionRegistrar的实现类,定义有具体的要注入的bean,写有注入bean的条件

/**
 * description:
 * author:dingyawu
 * date:created in 22:19 2020/12/5
 * history:
 */
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * AnnotationMetadata: 当前类的注解信息
     * BeanDefinitionRegistry:BeanDefinition注册类
     * 通过调用BeanDefinitionRegistry接口的registerBeanDefinition()方法,可以将所有需要添加到容器中的bean注入到容器中。
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){
        boolean user = registry.containsBeanDefinition(User.class.getName());
        boolean person = registry.containsBeanDefinition(Person.class.getName());
        if (user && person){
            BeanDefinition beanDefinition = new RootBeanDefinition(StudentBean.class);
            registry.registerBeanDefinition("studentBean", beanDefinition);
        }
    }
}

配置类:

/**
 * description:
 * 测试MyImportBeanDefinitionRegistrar,注入bean的时候用这种方式带条件注入
 * 个人理解也是mybatis等产品侵入spring的一种方式,是spring容器接入第三方产品的方式
 * author:dingyawu
 * date:created in 23:37 2020/12/4
 * history:
 */
@Configuration
@Import({User.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class PersonConfig10 {
}

测试demo:

/** 测试@import中MyImportBeanDefinitionRegistrar的用法 */
@Test
public void testMyImportBeanDefinitionRegistrar() {
  AnnotationConfigApplicationContext ac =
      new AnnotationConfigApplicationContext(PersonConfig10.class);
  String[] names = ac.getBeanDefinitionNames();
  Arrays.stream(names).forEach(System.out::println);
}

一般我们都是通过在@Import注解中使用ImportSelector接口或者ImportBeanDefinitionRegistrar来导入bean

ImportSelector接口是至spring中导入外部配置的核心接口,主要用来收集需要导入的配置类 通常我们会模拟实现@EnbaleXXX功能,在@EnbaleXXX这个注解上加入@Import注解