SpringBoot’s auto-configuration is so powerful, such as the @enable * annotation we often use to turn on support for certain aspects. So how does the @enable * annotation work?

The relationship between @enable * annotations and @import annotations

@ the Enable *, for example:

  • @enablescheduling Enable scheduled task support
  • @enableAsync Enables support for asynchronous methods
  • @enableAspectJAutoProxy Enables support for the AspectJ proxy
  • @ EnableTransactionManagement open support for the transaction
  • @enablecaching Enables the support for annotated caching

, etc.

If we look at the @enable * source code, we can see that all @enable * annotations are combined with @import annotations. The implementation of @enable * auto-enabled is actually importing some auto-configured beans

Take a look at the Spring Boot Reference Guide

You need not put all your @Configuration into a single class. The @Import annotation can be used to import additional configuration classes. You don't need to put all @Configuration into one class. The @import annotation imports additional configuration classes.Copy the code

The primary function of the @import annotation is to Import additional configuration information

The use of @import annotations

Official introduction:

* <p>Provides functionality equivalent to the {@code <import/>} element in Spring XML.
 * Allows for importing {@code @Configuration} classes, {@link ImportSelector} and
 * {@link ImportBeanDefinitionRegistrar} implementations, as well as regular component
 * classes (as of 4.2; analogous to {@link AnnotationConfigApplicationContext#register}).
Copy the code

There are three ways to use it

1. Import the @Configuration class directly.

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

}
Copy the code

Can see EnableScheduling annotations directly import the Configuration class SchedulingConfiguration, this kind of annotation @ the Configuration, and registered a scheduledAnnotationProcessor Bean, SchedulingConfiguration has the following source code:

@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class SchedulingConfiguration {

	@Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor(a) {
		return newScheduledAnnotationBeanPostProcessor(); }}Copy the code

2. Select the configuration class according to the condition (implement ImportSelector interface)

Use this method if you are not sure which configuration class to introduce and need to select one based on the class identified by the @import annotation or the definition information in another annotation (usually an annotation).

The ImportSelector interface has only one method

String[] selectImports(AnnotationMetadata importingClassMetadata);
Copy the code

AnnotationMetadata: Used to get annotations on the current configuration class

Ex. :

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

	Class<? extends Annotation> annotation() default Annotation.class;
	
	boolean proxyTargetClass(a) default false;

	AdviceMode mode(a) default AdviceMode.PROXY;

	int order(a) default Ordered.LOWEST_PRECEDENCE;

}

Copy the code

AdviceModeImportSelector AsyncConfigurationSelector inheritance, The AdviceModeImportSelector class implements the ImportSelector interface to select different beans based on the AdviceMode

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

3, dynamic registration Bean (implementation ImportBeanDefinitionRegistrar interface)

As long as the user knows exactly which beans to put into the container, they can be identified by spring annotations, such as @Component,@Service, @repository, @bean, etc. Class if it is not sure, or is not the spring is special, so don’t want to use the spring annotations for invasive logo, you can through the @ Import annotations, realize ImportBeanDefinitionRegistrar interface to dynamically register a Bean. Such as:

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

	boolean proxyTargetClass(a) default false;
	
	boolean exposeProxy(a) default false;

}
Copy the code

AspectJAutoProxyRegistrar ImportBeanDefinitionRegistrar interface is achieved, the ImportBeanDefinitionRegistrar is used at runtime automatically add Bean to an existing configuration class, through rewriting method:

public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
Copy the code
  • The AnnotationMetadata argument is used to get annotations on the current configuration class
  • The BeanDefinitionRegistry parameter is used to register beans

Source:

@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

The same is true of @Mapperscan in Mybatis

Official documents

The official documentation