As the mainstream framework of today's development, SpringBoot is impossible as a java developer. It is typical and easy to use, but when you understand the principle, you will unconsciously sigh, really TMNB!
This paper mainly explains the principle of its automatic assembly and how we use it in our daily life.
1, Conditional annotation
First, we create a Student object without any properties
public class Student { }
Then we establish a proposition:
If fastjson is imported into the project, the Student will be placed in the IOC. If not, it will not be loaded.
@SpringBootApplication public class SpringbootConditionApplication { public static void main(String[] args) { SpringApplication.run(SpringbootConditionApplication.class, args); } }
As shown in the figure above, this is the startup class (boot class) of springboot. Here, let's briefly talk about the run method of SpringApplication
We can see that the run method has a return value. The object is ConfigurableApplicationContext, which is a configuration context object. The IOC in spring is a context object. Therefore, we can see that through this context object, we can obtain our environment and beans in the IOC.
So we can write the code like this
@SpringBootApplication public class SpringbootConditionApplication { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(SpringbootConditionApplication.class, args); // Gets the bean named student Object student = context.getBean("student"); System.out.println(student); } }
At this time, we will write a class of StudentConfig to configure students, as follows
@Configuration public class StudentConfig { @Bean public Student student(){ return new Student(); } }
When we start the project, we can see that the project is successfully started directly
However, this does not meet our requirements, that is, there is a requirement to load student s only after importing fastjson in the project. At this time, the Condition annotation is required . The function of Conditional is that when you register a bean, you can add certain user-defined conditions to the bean. When this Condition is met, the bean is registered, otherwise it is not registered
Let's look at the code of Conditional
This annotation only defines an array of Class type, which is nothing. The point is that the generic type is required to be Condition
Then let's look at the interface of Condition
This interface only defines a method named matches and the return value is a boolean. At this time, it is not difficult to guess that when the value in the Conditional annotation is true, the annotated method will be executed. Here, we write another class to implement the Condition interface , You can see that the default return value is false, and then we will modify it slightly
public class ClassOnCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // Define a Boolean value boolean flag; try { // Find the class of fastjson through reflection Class<?> aClass = Class.forName("com.alibaba.fastjson.JSON"); // Returns true if found flag = true; } catch (ClassNotFoundException e) { // false if not found flag = false; } return flag; } }
Finally, don't forget to specify the class we just wrote in StudentConfig
@Configuration public class StudentConfig { @Bean @Conditional(ClassOnCondition.class) public Student student(){ return new Student(); } }
Then we annotate the dependencies in the project
Start the project, and sure enough, an error is reported, indicating that the student bean cannot be found
At this time, there must be witty children who may ask questions. If this path is written dead, it will be very coupled. Don't you make a dynamic loading?
Here, we can define an annotation called ConditionalOnClass, which defines an array, because there can be multiple set conditions
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional(ClassOnCondition.class) public @interface ConditionalOnClass { String[] value(); }
At this time, let's change the annotation in StudentConfig to our custom and pass in the value
@Configuration public class StudentConfig { @Bean // @Conditional(ClassOnCondition.class) @ConditionalOnClass("com.alibaba.fastjson.JSON") public Student student(){ return new Student(); } }
Finally, we are modifying the previously defined ClassOnCondition, but before modifying, let's talk about the two input parameters:
ConditionContext: this object is a context object, which can be used to obtain environment, ioc and class loader
AnnotatedtypeMetadata: annotation meta object, which can obtain the value passed in the annotation
We modify the code to the following figure
public class ClassOnCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // Define a Boolean value boolean flag; try { // Get the value from the annotation name Map<String, Object> map = metadata.getAnnotationAttributes(ConditionalOnClass.class.getName()); // Gets the value of value String[] classNames = (String[]) map.get("value"); for (String className : classNames) { Class<?> aClass = Class.forName(className); } flag = true; } catch (ClassNotFoundException e) { // false if not found flag = false; } return flag; } }
Canceling the fastjson dependency is still wrong
After joining, I successfully obtained
2, Application of Conditional annotation in spring boot
During the interview, the interviewer may ask how to limit in spring
This time
The spring boot version of this example is 2.6.1. We can find this project, spring boot autoconfigure
Find the condition folder of the project, and you can see many related annotations,
For example: ConditionOnProperty: when there are corresponding key value pairs in the configuration file, the corresponding methods will be executed
These are defined by springboot. We can use them directly. The effect is the same as that we just customized
Then we take kafka as an example to see how spring boot does
Find this class and let's look at the code
When 1 in the figure means that there is no bytecode file of KafkaTemplate in the project, the following 2 will not be executed
When 1 is satisfied, let's look at 2 (meaning that when there is no KafkaTemplate in the IOC container, the annotation method will be executed)
This is the usage of the Conditional annotation in springboot. In the next page, we will explain how to switch the Enable annotation in springboot.