Spring的@Import使用详解(干货)

  • Post author:
  • Post category:其他



@Import

注解可以用在@Configuration注解的类上,也可以用在普通的类上。它作为一个元注解,可以标记其他注解。

@Import

注解支持多种方式把Bean导入到IOC容器中:

  • 普通类 或

    @Configuration

    注解的类

  • ImportSelector

    的实现类

  • ImportBeanDefinitionRegistrar

    的实现类

Spring4.2 版本之前只可以导入配置类,之后就可以导入普通类了。

使用形式:

@Import(A.class)                               // 普通类导入
@Import(MyImportSelector.class)                // 需实现 ImportSelector 接口
@Import(MyImportBeanDefinitionRegister.class)  // 需实现 ImportBeanDefinitionRegistrar 接口



@Import导入普通类

public class User {
    private String name;
}

/**
    直接使用 @Import 导入User类到IOC容器中
*/
@Import(User.class)
public class Demo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annCtx = new AnnotationConfigApplicationContext(Demo.class);
        // 这种方式由于未定义 Bean的别名, getBean时只能用类的class去拿
        User bean = annCtx.getBean(User.class);
        System.out.println(bean);
    }
}

@Import(User.class) 这种是

直接导入普通类

的模式,我们的User类上就不需要任何注解(它就是一个最普通的Java类)



@Import+ImportSelector的实现

定义一个 MyImportSelector类,实现

ImportSelector

接口,重写

selectImports

方法。

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // 也可以配置 @Configuration 注解的配置类, 实现多个bean的加载
        return new String[]{"com.bean.User"};
    }
}

@Import(MyImportSelector.class)
public class Demo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annCtx = new AnnotationConfigApplicationContext(Demo.class);
        User bean = annCtx.getBean(User.class);
        System.out.println(bean);
    }
}

ImportSelector 模式可以一次性配置多个类,而且代码也比较清晰,只需要配置类全名即可。


SpringBoot自动配置 就是基于 @Import 的 ImportSelector实现的



@Import+ImportBeanDefinitionRegistrar

这种方式需要我们实现

ImportBeanDefinitionRegistrar

接口

// 实现 ImportBeanDefinitionRegistrar 接口, 主要对 BeanDefinition 进行操作
public class MyBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
    @Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 创建一个 BeanDefinition 类(即 Bean定义信息类), 用于接收 Java类
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
		// 把 User 注册为 Spring 的 <bean>, id 为 "user"
		registry.registerBeanDefinition("user", beanDefinition);
    }
}

@Import(MyBeanDefinitionRegister.class)
public class Demo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annCtx = new AnnotationConfigApplicationContext(Demo.class);
        User bean = annCtx.getBean(User.class);
        System.out.println(bean);
    }
}

有一个新的概念 BeanDefinition 简单理解就是 Bean的定义信息(Bean元数据),是需要IOC容器中进行管理的。

总之,创建一个Bean,首先需要读取 BeanDefinition 类,然后才能去创建Bean



ImportBeanDefinitionRegistrar 使用案例

ImportBeanDefinitionRegistrar的案例非常多,Spring 集成AspectJ AOP 就是使用了 ImportBeanDefinitionRegistrar。

  • 定义一个 @EnableAspectJAutoProxy 注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {       // 开启Aop切面的注解
    boolean proxyTargetClass() default false;
    boolean exposeProxy() default false;
}

该注解核心代码:@Import(AspectJAutoProxyRegistrar.class),这也是Spring集成其他功能通用方式

  • 实现 AspectJAutoProxyRegistrar 接口
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 注入 AspectJAnnotationAutoProxyCreator, 开启注解式AOP
        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
        
        // 读取 @EnableAspectJAutoProxy注解的相关属性
        AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        if (enableAspectJAutoProxy != null) {
            if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);  
            }
        }
    }
}
  • 代码中使用
@Configuration            //配置类
@EnableAspectJAutoProxy   //开启aop切面功能
public class AopConfig {
    
}



总结


@Import

使用非常广泛,我们经常看到的以

@Enable

开头的注解,如

@EnableAspectJAutoProxy



@EnableScheduling



@EnableCaching

等等,都是借助

@Import

实现的。



版权声明:本文为grb123原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。