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