Spring —— 关于 @Configuration @Import ImportSelector ImportBeanDefinitionRegistrar

Spring —— 关于 @Configuration @Import ImportSelector ImportBeanDefinitionRegistrar

前言

通常,@Import@Configuration 共同使用,用于在容器中注册对应的 BeanDefinition@Import 的属性值可以是

  1. 一个 配置类,此处的 配置类,可以是一个 @Configuration 注解标注的配置类(FULL 配置类)、一个标注了 @Import Component ComponentScan ImportResource 或者含有被 Bean 注解标注的方法(LITE 配置类)、甚至一个普通类
  2. 一个实现了 ImportSelector 的类
  3. 一个实现了 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配置类 下,AB依赖关系 将由 容器 处理

@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

ImportAspectJAutoProxyRegistrar 便是一个 ImportBeanDefinitionRegistrar,该类会帮我们注册一个 AnnotationAwareAspectJAutoProxyCreatorBeanDefinition,实现 AOP 代理

更多关于 AspectJAutoProxyRegistrar 的细节,
可以阅读下面文章

【源码】Spring AOP 14 原理解读三

总结

@Import@Configuration 的组合,是 Spring 很强大的配置方式,我们可以基于此实现灵活的 个性化配置

后来的 SpringBoot 也是大量的使用这种方式来实现灵活的配置,比如:自动装配

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值