This article, in the iteration from Spring 1. X to Spring 5.x, considers the development process of Spring annotation driven from the current perspective, which will help us better understand the annotation design in Spring.
Spring Framework 1.x
In the era of Spring Framework 1. X, 1.2.0 was the watershed of this era. At that time, Java 5 had just been released, and there was a technical trend of using Annotation in the industry. Naturally, the Spring Framework also provided support. For example, annotations such as @ Transactional had been supported at that time, but at this time, the XML configuration method was the only choice.
Add Bean declaration in xml
<bean name="testService" class="com.gupaoedu.controller.TestService"/>
test
public class XmlMain { public static void main(String[] args) { ApplicationContext context=new FileSystemXmlApplicationContext("classpath:applicationContext.xml"); TestService testService=(TestService)context.getBean("testService"); System.out.println(testService); } }
Spring Framework 2.x
In the Spring framework 2. X era, version 2.0 added @ Required, @ Repository, AOP related @ Aspect and other annotations in the Annotation. At the same time, it also improved the XML configuration capability, that is, extensible XML. For example, open source frameworks such as Dubbo are based on the extension of Spring XML to integrate Spring perfectly, thus reducing the threshold for Dubbo to use.
In the 2.x era, version 2.5 is also a watershed in this era. It introduces some core annotations
- Autowired dependency injection
- @Qualifier dependency lookup
- @Component, @ Service component declaration
- @Notes of spring mvc such as Controller, @ RequestMappring, etc
Although the Spring 2.x era provides many annotations, it still does not break away from the XML configuration driver, such as < context: Annotation config > < context: component scan >. The former is responsible for registering the Annotation processor, and the latter is responsible for scanning the classes marked by Spring schema annotations under the specified package path under the classpath and registering them as Spring beans
Define < context: component scan > in applicationContext.xml
<context:component-scan base-package="com.gupaoedu.controller"/>
Add annotation declaration
@Service public class TestService { }
Test class
public class XmlMain { public static void main(String[] args) { ApplicationContext context=new FileSystemXmlApplicationContext("classpath:applicationContext.xml"); TestService testService=(TestService)context.getBean("testService"); System.out.println(testService); } }
Spring Framework 3.x
Spring framework 3.0 is a milestone era, and its functional features began to be greatly extended, such as the full embrace of Java 5 and Spring Annotation. More importantly, it provides the Configuration class annotation @ Configuration. Its primary task is to replace the XML Configuration method. Unfortunately, spring framework 3.0 has not introduced the annotation to replace the XML element < context: component scan >, but chose a transitional method @ ImportResource.
@ImportResource allows you to import legacy XML configuration files, such as
@ImportResource("classpath:/META-INF/spring/other.xml") @Configuration public class SpringConfiguration{ }
In addition, AnnotationConfigApplicationContext registration is provided in spring framework d to register @ Configuration Class and assemble by parsing Configuration Class.
In version 3.1, @ ComponentScan is introduced to replace the XML element < context: component scan >. Although this annotation is a small upgrade, it is a great progress in the annotation driven field for spring. So far, it also reflects the unconfigured support of spring.
Configuration presentation
You should have used the annotation Configuration. It is an annotation used by the Configuration class based on the Spring IOC container in the form of JavaConfig. Because SpringBoot is essentially a spring application, it is normal to load the Configuration of IOC container through this annotation. So @ Configuration is marked in the startup class, which means that it is also a Configuration class of IOC container.
Take a very simple example
- Test code
ConfigurationDemo @Configuration public class ConfigurationDemo { @Bean public DemoClass demoClass(){ return new DemoClass(); } } DemoClass public class DemoClass { public void say(){ System.out.println("say: Hello Mic"); } } ConfigurationMain public class ConfigurationMain { public static void main(String[] args) { ApplicationContext applicationContext= new AnnotationConfigApplicationContext (ConfigurationDemo.class); DemoClass demoClass=applicationContext.getBean(DemoClass.class); demoClass.say(); } }
Component-scan
ComponentScan annotation is the most frequently used annotation, which is equivalent to < context: component scan > in the xml configuration file. Its main function is to scan the classes under the specified path, identify the classes to be assembled, and automatically assemble them into the Ioc container of spring.
The main forms of identifying the classes to be assembled are annotation identified classes such as @ Component, @ Repository, @ Service and @ Controller.
In the spring MVC project, create a separate package path and create an OtherServcie.
@Service public class OtherService { }
In the Controller, inject an instance of otherservice. When accessing this interface, an error will be reported, indicating that there is no otherservice instance.
@RestController public class HelloController { @Autowired OtherService otherService; @GetMapping("/hello") public String hello(){ System.out.println(otherService); return "Hello Gupaoedu"; } }
Add the concentration scan annotation, visit again, and solve the error.
@ComponentScan("com.gupaoedu")
ComponentScan will scan all classes marked with relevant annotations under the current package into the IoC container by default;
Import annotation
What does the import annotation mean? If you think of an annotation in the form of < import resource / > in xml, you can understand its role. Import is to merge multiple container configurations into one configuration. The meaning expressed in JavaConfig is the same.
Create a package and add a separate configuration to it
public class DefaultBean { } @Configuration public class SpringConfig { @Bean public DefaultBean defaultBean(){ return new DefaultBean(); } }
Run the test method at this time,
public class MainDemo { public static void main(String[] args) { ApplicationContext ac=new AnnotationConfigApplicationContext(SpringConfig.class); String[] defNames=ac.getBeanDefinitionNames(); for(String name:defNames){ System.out.println(name); } } }
Create a configuration class under another package path. At this time, run the previous test method again. When printing the OtherBean instance, an error will be reported, indicating that there is no such instance
public class OtherBean { } @Configuration public class OtherConfig { @Bean public OtherBean otherBean(){ return new OtherBean(); } }
Modify springConfig to import another configuration
@Import(OtherConfig.class) @Configuration public class SpringConfig { @Bean public DefaultBean defaultBean(){ return new DefaultBean(); } }
- Run the test method again to see the output of the object instance.
So far, we have learned that the Spring Framework completely replaces XML in the annotation driven era. So far, has the Spring team stopped? You are too simple. Although non configuration can reduce the trouble caused by configuration maintenance, there will still be basic configuration statements for third-party organizations. It is also cumbersome, so Spring exits the @ Enable module driver. The function of this feature is to assemble functional components with the same responsibilities in a modular way, which further simplifies the configuration of Spring beans.
Enable module driver
We implement the function of a scheduled task through the scheduled task mechanism provided by spring, and demonstrate the difference between using Enable annotation and not using Enable. Let's feel the role of some Enable annotations.
Before using EnableScheduing
Add the configuration of scheduled scheduling in applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.gupaoedu.controller"/> <!--AnnotationDrivenBeanDefinitionParser--> <task:annotation-driven scheduler="scheduler"/> <!-- timer switch --> <task:scheduler id="scheduler" pool-size="5"/> </beans>
Writing task processing classes
@Service public class TaskService { @Scheduled(fixedRate = 5000) //The method is declared as a Scheduled task by @ Scheduled, and is executed at fixed intervals using the fixedRate property public void reportCurrentTime(){ System.out.println("Every 5 seconds "+new Date()); } }
Writing test classes
public class TestTask { public static void main(String[] args) { ApplicationContext applicationContext=new FileSystemXmlApplicationContext("classpath:applicationContext.xml"); } }
After using EnableScheding
Create a configuration class
@Configuration @ComponentScan("com.gupaoedu.controller") @EnableScheduling public class SpringConfig { }
Create a service
@Service public class TaskService { @Scheduled(fixedRate = 5000) //The method is declared as a Scheduled task by @ Scheduled, and is executed at fixed intervals using the fixedRate property public void reportCurrentTime(){ System.out.println("Every 5 seconds "+new Date()); } }
Create a main method
public class TaskMain { public static void main(String[] args) { ApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class); } }
- Start the service to realize the function of scheduled scheduling.
Think about which steps are omitted using Enable?
First, let's look at the code that doesn't use Enable. There will be one in it
<task:annotation-driven scheduler="scheduler"/>
The scheduler is annotation driven and will be parsed by the parser annotation driven bean definition parser.
In the parse method, the following code is defined
builder = BeanDefinitionBuilder.genericBeanDefinition("org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor"); builder.getRawBeanDefinition().setSource(source);
This class is used to parse the @ Scheduled annotation.
ok, let's take another look at the enableshcheduling annotation. We can see that it will automatically register a bean of ScheduledAnnotationBeanPostProcessor. Therefore, through this example, we want to express the function of the Enable annotation, which can help us omit the declared configuration of some third-party module beans.
public class SchedulingConfiguration { public SchedulingConfiguration() { } @Bean( name = {"org.springframework.context.annotation.internalScheduledAnnotationProcessor"} ) @Role(2) public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() { return new ScheduledAnnotationBeanPostProcessor(); } }
Spring Framework 4.x
Spring 4.x version is a perfect era of annotation. It mainly improves the Conditional assembly ability, introduces @ Conditional annotation, and realizes cooperation through custom conditions, making up for the shortcomings of Conditional configuration in previous versions.
In short, Conditional provides a Bean loading condition judgment, that is, if this condition is not met, the objects declared through @ Bean will not be loaded automatically. How to use it?, First, let's briefly take you to understand its basic use.
Overview of Conditional
@Condition al is an annotation. Let's look at the declaration of this annotation, which can receive an array of conditions.
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Conditional { Class<? extends Condition>[] value(); }
@FunctionalInterface public interface Condition { boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2); }
This Condition is a functional interface that provides a matchers method. In short, it provides a matching judgment rule. Returning true means that beans can be injected, and returning false means that beans cannot be injected.
Actual combat of Conditional
Customize a Condition. The logic is relatively simple. If the current operating system is Windows, it returns true; otherwise, it returns false
public class GpCondition implements Condition{ @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { //Judge the condition here. If true is returned, it means that the configuration class or Bean needs to be loaded //Otherwise, it means no loading String os=conditionContext.getEnvironment().getProperty("os.name"); if(os.contains("Windows")){ return true; } return false; } }
Create a configuration class and load a BeanClass
@Configuration public class ConditionConfig { @Bean @Conditional(GpCondition.class) public BeanClass beanClass(){ return new BeanClass(); } }
- Add @ Conditional(GpCondition.class) to the bean declaration method of BeanClass. The specific condition is our custom GpCondition class. The above code means that if matches in the GpCondition class returns true, BeanClass will be loaded into the Spring IoC container
Run test method
public class ConditionMain { public static void main(String[] args) { AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(ConditionConfig.class); BeanClass beanClass=context.getBean(BeanClass.class); System.out.println(beanClass); } }
summary
After the overall analysis of Spring annotation driven, it is not difficult to find that the reason why we can easily complete a large number of functions in Spring based on annotations is due to the efforts of the Spring team to continuously solve the user pain points.
The automatic assembly mechanism of Spring Boot is also evolved on the basis of Spring annotation driven. In the subsequent content, I will specifically analyze the automatic assembly mechanism of Spring Boot.
Copyright notice: unless otherwise stated, all articles on this blog adopt CC BY-NC-SA 4.0 license agreement. Reprint please indicate from Mic to take you to learn architecture!
If this article is helpful to you, please pay attention and praise. Your persistence is the driving force of my continuous creation. Welcome to WeChat public official account for more dry cargo.