Spring —— 关于 @Configuration @Import ImportSelector ImportBeanDefinitionRegistrar
前言
通常,@Import
和 @Configuration
共同使用,用于在容器中注册对应的 BeanDefinition,@Import
的属性值可以是
- 一个 配置类,此处的 配置类,可以是一个
@Configuration
注解标注的配置类(FULL 配置类)、一个标注了@Import
Component
ComponentScan
ImportResource
或者含有被Bean
注解标注的方法(LITE 配置类)、甚至一个普通类 - 一个实现了 ImportSelector 的类
- 一个实现了 ImportBeanDefinitionRegistrar 的类
@Configuration
被 @Configuration
标注的类,通常称为 配置类,但配置类,并不单单指标注了 @Configuration
的类
- 标注了
@Configuration
的配置类,称为 FULL 配置类,在 FULL 配置类中注册的 组件类,会在ConfigurationClassPostProcessor#postProcessBeanFactory
方法中被 ConfigurationClassEnhancer 代理,交由 容器 处理依赖关系 - 而对于没有标注
@Configuration
,但是标注了@Import
Component
ComponentScan
ImportResource
或者含有被Bean
注解标注方法的配置类,称为 LITE 配置类 - 对于 FULL配置类 和 LITE配置类,ConfigurationClassPostProcessor 会委托 ConfigurationClassParser 类解析处理对应的
Component
@PropertySource
@ComponentScan
@Import
@ImportResource
注解以及标注了@Bean
的方法
FULL & LITE
FULL配置类 & LITE配置类 的区别,可以看以下示例体会
public class A {
public A() {
System.out.println("...A");
}
}
public class B {
public B(A a) {
System.out.println("...B");
}
}
@Configuration
@ComponentScan("com.xsn.configurationtest")
public class MyConfigurationConfig {
@Bean
public A a() {
return new A();
}
@Bean
public B b() {
return new B(a());
}
}
public static void main(String[] args) {
AnnotationConfigApplicationContext ac =
new AnnotationConfigApplicationContext(MyConfigurationConfig.class);
A a = ac.getBean(A.class);
System.out.println(a);
B b = ac.getBean(B.class);
System.out.println(b);
}
结果:
FULL配置类(加了 @Configuration):
...A
...B
LITE配置类(注释掉 @Configuration):
...A
...A
...B
可以看到在 FULL配置类 下,A 和 B 的 依赖关系 将由 容器 处理
@Import
@Import
和 @Configuration
共同使用,用于在容器中注册对应的 BeanDefinition
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
Class<?>[] value();
}
配置类
public class C {
public C() {
System.out.println("...c");
}
}
@Configuration
@ComponentScan("com.xsn.configurationtest")
@Import(C.class)
public class MyConfigurationConfig {
}
public static void main(String[] args) {
AnnotationConfigApplicationContext ac =
new AnnotationConfigApplicationContext(MyConfigurationConfig.class);
C c = ac.getBean(C.class);
System.out.println(c);
}
结果:
com.xsn.configurationtest.C@71ba6d4e
类 C 就是一个普通类,同样也可以 Import 一个配置类(FULL & LITE),如下
@Configuration
@Import(C.class)
public class ImportConfiguration {
}
@Configuration
@ComponentScan("com.xsn.configurationtest")
@Import(ImportConfiguration.class)
public class MyConfigurationConfig {
}
public static void main(String[] args) {
AnnotationConfigApplicationContext ac =
new AnnotationConfigApplicationContext(MyConfigurationConfig.class);
C c = ac.getBean(C.class);
System.out.println(c);
}
结果:
com.xsn.configurationtest.C@71ba6d4e
ImportSelector
同样,@Import
注解可以 Import 一个 ImportSelector 的实现类
public interface ImportSelector {
// 返回要 Import 的配置类名
String[] selectImports(AnnotationMetadata importingClassMetadata);
// 允许提供一个 Predicate 过滤 selectImports 方法对应的类
@Nullable
default Predicate<String> getExclusionFilter() {
return null;
}
}
类似于直接 Import 配置类,但是 ImportSelector 的实现类可以基于对应配置类的 AnnotationMetadata 属性进行 select
,同时还可以实现各种 Aware 接口类似 EnvironmentAware BeanFactoryAware 等,持有对应的 Environment BeanFactory 来进行 select
示例
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
StandardAnnotationMetadata standardAnnotationMetadata
= (StandardAnnotationMetadata) importingClassMetadata;
return new String[]{"com.xsn.configurationtest.C"};
}
@Override
public Predicate<String> getExclusionFilter() {
return null;
}
}
@Configuration
@ComponentScan("com.xsn.configurationtest")
@Import(MyImportSelector.class)
public class MyConfigurationConfig {
}
public static void main(String[] args) {
AnnotationConfigApplicationContext ac =
new AnnotationConfigApplicationContext(MyConfigurationConfig.class);
C c = ac.getBean(C.class);
System.out.println(c);
}
结果:
com.xsn.configurationtest.C@5ab956d7
DeferredImportSelector
DeferredImportSelector 继承了 ImportSelector,当 Import 的是一个 DeferredImportSelector 时,该 DeferredImportSelector 会在最后解析,主要用于有 @Conditional
注解的配置类
ImportBeanDefinitionRegistrar
同样,@Import
注解可以 Import 一个 ImportBeanDefinitionRegistrar 的实现类
public interface ImportBeanDefinitionRegistrar {
// 基于 AnnotationMetadata BeanDefinitionRegistry 注册对应的 BeanDefinition
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
BeanNameGenerator importBeanNameGenerator) {
registerBeanDefinitions(importingClassMetadata, registry);
}
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
}
}
ImportBeanDefinitionRegistrar 也可以实现各种 Aware 接口类似 EnvironmentAware BeanFactoryAware 等,持有对应的 Environment BeanFactory 来进行 register
我们使用 Spring AOP 时,在配置类上添加的 @EnableAspectJAutoProxy
注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy
它 Import 的 AspectJAutoProxyRegistrar 便是一个 ImportBeanDefinitionRegistrar,该类会帮我们注册一个 AnnotationAwareAspectJAutoProxyCreator 的 BeanDefinition,实现 AOP 代理
更多关于 AspectJAutoProxyRegistrar 的细节,
可以阅读下面文章
总结
@Import
和 @Configuration
的组合,是 Spring 很强大的配置方式,我们可以基于此实现灵活的 个性化配置
后来的 SpringBoot 也是大量的使用这种方式来实现灵活的配置,比如:自动装配