Spring 3.1 new feature 2: @ enable * annotation source code and many enable annotations

@enable * annotation
When analyzing the automatic configuration principle of SpringBoot, you can observe the source code of these @ Enable * annotations and find that all annotations have an @ Import annotation@ The Import annotation is used to Import configuration classes, which means that these automatically enabled implementations actually Import some automatically configured beans.
For example, freemarker's automatic configuration class FreeMarkerAutoConfiguration requires some classes in classloader to exist and load after other configuration classes.

However, there are some automatic configuration classes that need to use some annotation switches to take effect. For example, @ EnableBatchProcessing annotation and @ EnableCaching in spring boot starter batch.
1, Automatic injection example
Define an Annotation. Enablecontent service allows the class using this Annotation to inject some classes or do some underlying things.
Use the @ Import annotation provided by Spring together with a configuration class to complete.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(ContentConfiguration.class)
public @interface EnableContentService {}

public interface ContentService {
    void doSomething();
}

public class SimpleContentService implements ContentService {
    @Override
    public void doSomething() {
        System.out.println("do some simple things");
    }
}

Then add the @ enablecontent service annotation at the entry of the application.

In this way, ContentService is injected. SpringBoot is completed with this. It just uses a more advanced ImportSelector.
@How to use Import.
Class 1: direct import configuration class
For example, the @ enableshcheduling directly imports the Configuration class SchedulingConfiguration, which annotates @ Configuration and registers a Bean of scheduledAnnotationProcessor

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

Type II: select the configuration type according to the conditions
For example, in @ EnableAsync, through asyncconfigurationselector Class configuration.

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

}

AsyncConfigurationSelector selects the configuration class to be imported through conditions. The root interface of AsyncConfigurationSelector is ImportSelector. This interface needs to override the selectImports method, and make pre condition judgment in this method.

If the adviceMode is portxy, the configuration class ProxyAsyncConfiguration is returned.

If activeMode is ASPECTJ, return AspectJAsyncConfiguration configuration class.

The key methods are as follows:

public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {

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

    /**
     * {@inheritDoc}
     * @return {@link ProxyAsyncConfiguration} or {@code AspectJAsyncConfiguration} for
     * {@code PROXY} and {@code ASPECTJ} values of {@link EnableAsync#mode()}, respectively
     */
    @Override
    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;
        }
    }

}

Class III: dynamically registered beans
Enableaspectjautoproxy in spring java

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
    boolean proxyTargetClass() default false;
    boolean exposeProxy() default false;
}

Aspectjautoproxyregister implements the importbeandefinitionregister interface. Importbeandefinitionregister is used to automatically add beans to existing configuration classes at run time. By rewriting the method:

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.getBoolean("proxyTargetClass")) {
            AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
        }
        if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
            AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
        }
    }

}

The AnnotationMetadata parameter is used to obtain the annotation on the current configuration class;

The beandefinitionregistry parameter is used to register beans.

Use of ImportSelector in SpringBoot
The ImportSelector in SpringBoot is completed through the annotation @ EnableAutoConfiguration provided by SpringBoot.

This @ EnableAutoConfiguration annotation can be called explicitly, otherwise it will be called implicitly in the @ SpringBootApplication annotation.
@EnableAutoConfiguration annotation uses EnableAutoConfigurationImportSelector as ImportSelector. The following code is the specific code for selection in EnableAutoConfigurationImportSelector:

@Override
public String[] selectImports(AnnotationMetadata metadata) {
    try {
        AnnotationAttributes attributes = getAttributes(metadata);
        List<String> configurations = getCandidateConfigurations(metadata,
                attributes);
        configurations = removeDuplicates(configurations); // Delete duplicate configuration
        Set<String> exclusions = getExclusions(metadata, attributes); // Remove the configuration that requires exclude
        configurations.removeAll(exclusions);
        configurations = sort(configurations); // sort
        recordWithConditionEvaluationReport(configurations, exclusions);
        return configurations.toArray(new String[configurations.size()]);
    }
    catch (IOException ex) {
        throw new IllegalStateException(ex);
    }
}

The getCandidateConfigurations method will get the configuration class:

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
        AnnotationAttributes attributes) {
    return SpringFactoriesLoader.loadFactoryNames(
            getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
}

SpringFactoriesLoader. The loadfactorynames method is based on facts_ RESOURCE_ The static variable location reads meta-inf / spring.exe from all jar packages Factories file information:

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();
    try {
        Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
        List<String> result = new ArrayList<String>();
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
            String factoryClassNames = properties.getProperty(factoryClassName); // Only the value whose key is factoryClassNames will be filtered out
            result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
        }
        return result;
    }
    catch (IOException ex) {
        throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
                "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
}

The getspringfactoryesloaderfactoryclass method in the getCandidateConfigurations method returns enableautoconfiguration Class, so the key will be filtered out as org springframework. Boot autoconfigure. The value of enableautoconfiguration.

The following configuration code is spring.com in the jar package of autoconfigure Part of the contents of the factories file (a key is org.springframework.boot.autoconfigure.EnableAutoConfiguration, so you will get these autoconfigurations):

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\......

Of course, not all of these autoconfigurations will be loaded. Whether to load them will be determined according to @ ConditionalOnClass and other conditions on AutoConfiguration.

In the above example, when reading the properties file, the key will only be filtered out as org springframework. Boot autoconfigure. The value of enableautoconfiguration.

There are other key s in SpringBoot to filter the classes to be loaded:

org.springframework.test.context.TestExecutionListener

org.springframework.beans.BeanInfoFactory

org.springframework.context.ApplicationContextInitializer

org.springframework.context.ApplicationListener

org.springframework.boot.SpringApplicationRunListener

org.springframework.boot.env.EnvironmentPostProcessor

org.springframework.boot.env.PropertySourceLoader

@ Enable in spring*

@EnableAspectJAutoProxy
@EnableAspectJAutoProxy annotation activates Aspect automatic proxy. Using @ EnableAspectJAutoProxy is equivalent to < AOP: AspectJ AutoProxy / > enabling AspectJ automatic proxy.

@EnableAsync
@The EnableAsync annotation turns on support for asynchronous methods.

See @ Async realizing asynchronous call Add link description

@EnableScheduling
@The enablesscheduling annotation enables support for scheduled tasks.

See Spring's @ Scheduled task scheduling for an example Add link description

@EnableWebMVC
@The EnableWebMVC annotation is used to enable the configuration support of Web MVC.

That is, it will be used when writing Spring MVC.

@EnableConfigurationProperties
@The EnableConfigurationProperties annotation is used to enable the @ ConfigurationProperties annotation to configure beans.

@EnableJpaRepositories
@The EnableJpaRepositories annotation enables support for spring data JPA repository.
Spring Data JPA framework is mainly aimed at the only business logic code that spring has not simplified. So far, developers have saved the only work left to implement the business logic of the persistence layer. The only thing to do is to declare the interface of the persistence layer, and the rest will be handed over to Spring Data JPA to help you!
Simply put, Spring Data JPA is a framework for persisting data.

@EnableTransactionManagement
@The enable transaction management annotation enables support for annotated transactions.

The @ EnableTransactionManagement annotation informs Spring that the @ Transactional annotated class is surrounded by the transaction aspect. So @ Transactional can be used.

@EnableCaching
@The EnableCaching annotation enables annotated caching support

Tags: Spring

Posted by acrayne on Fri, 15 Apr 2022 12:32:35 +0930