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

@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实现的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值