“This is the third day of my participation in the First Challenge 2022. For details: First Challenge 2022”
Spring has such one kind comments begin with the Enable, for example: @ EnableAsync, @ EnableWebMvc, @ EnableTransactionManagement, etc., in these three works in see more and more common one. From the point of annotation literally, is mainly used to open a function, such as: @ EnableTransactionManagement annotations are open transaction management, then add @ Transactional annotation is used. It is not enough to just use the annotations provided by Spring in the process of working, so we need to make a custom Enable annotation to Enable a feature and then use it with the corresponding annotation. Here’s how to customize Enable type annotations, followed by extensions of AOP type annotations.
1. Explain the @enable annotation principle
The process for parsing @enable annotations is as follows:
From the @enable annotation’s parsing flow chart, we can analyze the principle:
- The entrance to the annotation of parsing ConfigurationClassPostProcessor, this class is BeanDefinitionRegistryPostProcessor the implementation of the interface, The inherited spring BeanFactoryPostProcessor BeanDefinitionRegistryPostProcessor interface. (Spring container startup calls BeanFactoryPostProcessor’s set of related methods for inheriting and implementing instances.)
- ConfigurationClassPostProcessor derives from the Spring container is decorated @ the Configuration class, and then to new ConfigurationClassParser instance.
- ConfigurationClassParser takes care of that @Component, @propertysources, @Propertysource, @ComponentScans, @ImportResource, @Configuration @ Import.
- @import is the entry point for the @enable annotation, @ the configuration of the Import Import class needs to implement DeferredImportSelector, ImportSelector, ImportBeanDefinitionRegistrar One of the three classes that we use to inject our own implementation-related classes into the Spring container for our own implementation purposes
Use Spring to parse the @configuration class, and then parse the @import annotation on the class to configure the value interface. These classes are implemented DeferredImportSelector, ImportSelector, ImportBeanDefinitionRegistrar one of the three interfaces. The implementation of the three interfaces is done here by registering our custom classes with the Spring container.
Tpis: Spring-native annotations and interfaces used in custom Enable
annotations
@ Configuration, @ Import
interface
DeferredImportSelector, ImportSelector, ImportBeanDefinitionRegistrar
2. Customize the @enable annotation practice
A custom @enablelog annotation is used to enable or disable logging. Customization requires the following steps:
2.1 Define the @enable annotation
@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface EnableLog {
boolean value(a) default true;
/**
* use asynchronization method to record log
* @return* /
boolean async(a) default false;
/**
* log name
* @return* /
String loggerName(a) default "";
boolean proxyTargetClass(a) default false;
}
Copy the code
Attributes in annotations can be defined according to the functionality implemented.
2.2 Interface Implementation
You need to implement any one of three interfaces:
- ImportSelector
- DeferredImportSelector
- ImportBeanDefinitionRegistrar
ImportSelector and DeferredImportSelector are in the same class of interfaces that execute at different times. ImportBeanDefinitionRegistrar to inject BeanDefinition in the Spring container. The three interfaces are selected to see what is needed to implement the functionality. The ImportSelector we use here (which is also the most common) :
public class LogImportSelector implements ImportSelector {
/**
* Select and return the names of which class(es) should be imported based on the {@link AnnotationMetadata} of the
* importing @{@link Configuration} class.
*
* @param importingClassMetadata
* @return the class names, or an empty array if none
*/
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableLog.class.getName(), false));
boolean value = attributes.getBoolean("value");
if (value) {
return new String[]{LogConfig.class.getName(), LogImportBeanDefinitionRegistrar.class.getName()};
}
return new String[0]; }}Copy the code
Here in the Spring container injects a LogConfig configuration class, as well as a LogImportBeanDefinitionRegistrar class.
- LogConfig: An AOP-related class instance used primarily to configure logging
- LogImportBeanDefinitionRegistrar: open the processing of AOP, and Spring used in the process of log processing way of acting
The code will be explained in detail in AOP based extension
2.3 Custom Annotations Added the @import annotation
The custom @enablelog annotation above defines a common annotation, so how to integrate with Spring requires the @import annotation.
@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Import(LogImportSelector.class) (1)
public @interface EnableLog {
// Omit some code
}
Copy the code
Add the code for position (1). Here you combine custom annotations with the Spring framework. At this point, @enablelog customization is complete.
2.4 Used with @Configuration
The custom Enable annotation needs to be used with the Spring-native @Configuration annotation (the principle is described above).
@EnableLog
@Configuration
public class EnableLogConfig {}Copy the code
The above code can then be used.
If you are a SpringBoot project, you can put it directly on top of the @SpringBootApplication annotation class. The reason is that the @SpringBootConfiguration annotation has the @Configuration annotation configured on it. That’s why @SpringBootApplication is like an @Configuration annotation, so our custom Enable annotation can be placed directly on @SpringBootApplication, You can also customize a class with @Configuration.
The code will be presented in a subsequent article. This involves the extension of AOP.
3. Summary
- Annotations of the Enable type are equivalent to a switch in terms of both Spring native and its own extension. Increase this annotation is opened a function, need to match other annotations to use, for example: @ @ Async annotation EnableAsync collocation, @ @ EnableTransactionManagement collocation Transactional annotation is used
- The @Configuration annotation is required for Enable annotations to take effect
- Enable the realization of type annotations need to match the annotation @ Import Import, function implementation needs to implement DeferredImportSelector, ImportSelector, ImportBeanDefinitionRegistrar a three interfaces.
Implement custom Enable type annotations using Spring’s native annotations and some specific extension interfaces.