The magic @ Enable * annotation in SpringBoot?

Keywords: Java Spring Attribute Redis

In the spring boot development process, we often encounter many annotations from @ Enable, such as @ EnableEurekaServer, @ EnableAsync, @ EnableScheduling, etc. today, we will analyze how these annotations work.

Contents of this article

I. principle of @ Enable *II. Usage of @ Import annotation1. Import configuration class directly2. Select configuration class according to conditions3. Dynamically register Bean

I. principle of @ Enable *

From the source code of these @ Enable * annotations, we can see that there is an @ Import annotation in all @ Enable * annotations, and @ Import is used to Import configuration classes, so the implementation principle of @ Enable * auto opening is to Import some auto configured beans.

II. Usage of @ Import annotation

@Import annotation allows to import the implementation classes of @ Configuration class, ImportSelector and importbeandefinitionregister, which are equivalent to normal component classes.

There are three ways to use it

1. Import configuration class directly

@EnableEurekaServer uses this method. The annotation source code is as follows:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({EurekaServerMarkerConfiguration.class})
public @interface EnableEurekaServer {
}

You can see that the @ EnableEurekaServer annotation directly imports the configuration class eurekasermarkerconfiguration, which registers a Bean of eurekasermarkerconfiguration with the spring container.

The source code of EurekaServerMarkerConfiguration is as follows:

@Configuration
public class EurekaServerMarkerConfiguration {
    public EurekaServerMarkerConfiguration() {
    }

    @Bean
    public EurekaServerMarkerConfiguration.Marker eurekaServerMarkerBean() {
        return new EurekaServerMarkerConfiguration.Marker();
    }

    class Marker {
        Marker() {
        }
    }
}

2. Select configuration class according to conditions

@EnableAsync uses this method. The annotation source code is as follows:

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

    Class<? extends Annotation> annotation() default Annotation.class;

    boolean proxyTargetClass() default false;

    AdviceMode mode() default AdviceMode.PROXY;

    int order() default Ordered.LOWEST_PRECEDENCE;
}

The AsyncConfigurationSelector is imported in the EnableAsync annotation. The AsyncConfigurationSelector selects the configuration classes to be imported by conditions, inherits the AdviceModeImportSelector and implements the ImportSelector interface. The interface rewrites the selectImports method to determine the PROXY or ASPECTJ to select different configuration classes in advance.

The source code of AsyncConfigurationSelector is as follows:

public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync{

    private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
            "org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";


    /**
     * Returns {@link ProxyAsyncConfiguration} or {@code AspectJAsyncConfiguration}
     * for {@code PROXY} and {@code ASPECTJ} values of {@link EnableAsync#mode()},
     * respectively.
     */

    @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;
        }
    }

}

3. Dynamically register Bean

@EnableAspectJAutoProxy uses this method. The annotation source code is as follows:

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

    boolean proxyTargetClass() default false;

    boolean exposeProxy() default false;
}

In the EnableAspectJAutoProxy annotation, the aspectjautoproxyregister is imported, and the aspectjautoproxyregister implements the importbeandefinitionregister interface to register the Bean into the spring container at runtime.

The source code of aspectjautoproxyregister is as follows:

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * Register, escalate, and configure the AspectJ auto proxy creator based on the value
     * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
     * {@code @Configuration} class.
     */

    @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);
            }
        }
    }

}

Recommended reading

1. In Java, Integer.parseInt and Integer.valueOf, are you still confused?
2. Spring cloud series - two ways to integrate Hystrix)
3. Spring cloud series - Implementing declarative service invocation with Feign)
4. Take your hands with you and use the Ribbon to realize the load sharing of the client.
5. Spring cloud sets up registration center and service registration

Collect free Java related materials in limited time, covering Java, Redis, MongoDB, MySQL, Zookeeper, Spring Cloud, Dubbo/Kafka, Hadoop, Hbase, Flink and other high concurrent distributed, big data, machine learning and other technologies.
Pay attention to the following public ID and get it free of charge:

Java fragment public account

 

Posted by nalkari on Wed, 23 Oct 2019 18:46:26 -0700