@ Import annotations

The @import annotation provides the equivalent of the < Import /> element in XML to implement one or more imported configuration classes. @import can be used either on a class or as a meta-annotation.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {

	/ * * * {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
	 * or regular component classes to import.
	 */Class<? >[] value(); }Copy the code

There is only one value() in the annotation; . Support the import @ the Configuration with the Configuration of the class, realize ImportSelector interface, realize ImportBeanDefinitionRegistrar interface and ordinary @ component class.

Used as meta-annotations

@import can be used as a meta-annotation that encapsulates a layer over the inheritance of @import. It is my understanding that this will not expose my internal implementation details to the outside world.

An example: the @enableAspectJAutoProxy annotation.

@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
Copy the code

@enableaspectjautoproxy is marked by the @import meta annotation, and we (programmers) EnableAspectJAutoProxy by using @enableaspectjautoproxy, Spring’s bottom layer is implemented by importing the corresponding configuration class via @import.

Import the class that implements the ImportSelector interface

Take a look at the ImportSelector interface, which has only one method:

public interface ImportSelector {
	String[] selectImports(AnnotationMetadata importingClassMetadata);
}
Copy the code

ImportSelector, input selector. This interface is used to select which configuration classes to import based on given conditions.

For example: such as @ EnableTransactionManagement annotation.

@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
Copy the code

In @ EnableTransactionManagement annotations using the @ Import TransactionManagementConfigurationSelector. Class notes, The TransactionManagementConfigurationSelector class is implemented ImportSelector interface.

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY:
				return new String[] {AutoProxyRegistrar.class.getName(),
						ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {
						TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
			default:
				return null; }}}Copy the code

The internal implementation logic of the method is also very simple, which is to import different configuration classes according to different AdviceMode to achieve transaction management.

Import ImportBeanDefinitionRegistrar interface classes

ImportBeanDefinitionRegistrar interface also is only one way:

public interface ImportBeanDefinitionRegistrar {
	void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}
Copy the code

This interface allows us to register additional BeanDefinitions on demand based on the annotation metadata given.

An example: the @enableAspectJAutoProxy annotation.

@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
Copy the code

@ EnableAspectJAutoProxy annotations introduced AspectJAutoProxyRegistrar class class, this class is to implement the ImportBeanDefinitionRegistrar interface.

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	@Override
	public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if(enableAspectJAutoProxy ! =null) {
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); }}}}Copy the code

RegisterBeanDefinitions calls the AopConfigUtils. RegisterAspectJAnnotationAutoProxyCreatorIfNecessary (registry); Method, which is to register a BeanDefinition in the BeanDefinitionRegistry registry passed in. Once BeanDefinition is registered, Spring instantiates the Bean to achieve the AspectJAutoProxy effect.

Import @ the Configuration class

This time @import is most commonly used as a method. We can split the configuration classes and import the corresponding configurations as needed in the program.

For example: the @enableretry annotation. Use this annotation to enable the retry feature.

@EnableAspectJAutoProxy(proxyTargetClass = false)
@Import(RetryConfiguration.class)
public @interface EnableRetry {
Copy the code

Inside it is the RetryConfiguration class imported.

ImportAware interface

The ImportAware interface is required in conjunction with @import. When @import is used as a meta-annotation, a configuration class imported through @import that implements the ImportAware interface can obtain the data configuration imported into the configuration class interface. It’s a little convoluted, so let’s just go to the code.

An example is the @enableAsync annotation.

@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
Copy the code
/ / AsyncConfigurationSelector source code
public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {

	private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
			"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";
	@Override
	@Nullable
	public String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY:
				return new String[] {ProxyAsyncConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
			default:
				return null; }}}Copy the code

By default, AdviceMode is used as PROXY and ProxyAsyncConfiguration class is imported.

@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration {

	@Bean(name = TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public AsyncAnnotationBeanPostProcessor asyncAdvisor(a) {
		Assert.notNull(this.enableAsync, "@EnableAsync annotation metadata was not injected");
		AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
		Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");
		if(customAsyncAnnotation ! = AnnotationUtils.getDefaultValue(EnableAsync.class,"annotation")) {
			bpp.setAsyncAnnotationType(customAsyncAnnotation);
		}
		if (this.executor ! =null) {
			bpp.setExecutor(this.executor);
		}
		if (this.exceptionHandler ! =null) {
			bpp.setExceptionHandler(this.exceptionHandler);
		}
		bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
		bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));
		returnbpp; }}Copy the code

In the asyncAdvisor method of ProxyAsyncConfiguration, you need to obtain some Settings on @enableAsync, for example: This. EnableAsync. GetBoolean (” proxyTargetClass “), enclosing enableAsync. < Integer > getNumber (” order “).

This enableAsync is its parent class AbstractAsyncConfiguration properties. AbstractAsyncConfiguration ImportAware interface is achieved, which can get @ EnableAsync on information.

/ / AbstractAsyncConfiguration# setImportMetadata source code
public void setImportMetadata(AnnotationMetadata importMetadata) {
	this.enableAsync = AnnotationAttributes.fromMap(
			importMetadata.getAnnotationAttributes(EnableAsync.class.getName(), false));
	if (this.enableAsync == null) {
		throw new IllegalArgumentException(
				"@EnableAsync is not present on importing class "+ importMetadata.getClassName()); }}Copy the code

If this example is a bit complicated, there is a slightly simpler one: EnableRedisHttpSession. For this, you can check out source debug for yourself.


Thank you for following wechat public account: