“This is the 26th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”
This article, in the Spring1.x to Spring 5.x iterations, takes a look at Spring’s annotation-driven evolution from its present perspective, which will help us better understand annotation design in Spring.
Spring Framework 1.x
In the era of Spring framework1.x, 1.2.0 was the watershed of this era. At that time, Java5 was just released, the technology trend of using annotations was emerging, and the SpringFramework also provided support. Annotations such as @Transactional were already supported, but at this point XML configuration was the only option.
-
Add a Bean declaration to the XML
<bean name="testService" class="com.gupaoedu.controller.TestService"/> Copy the code
-
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); }}Copy the code
Spring Framework 2.x
Spring Framework2.x version 2.0 adds @required, @Repository, and aOP-related @aspect annotations to annotations, and also improves XML configuration capabilities, i.e. extensible XML. Open source frameworks such as Dubbo are based on Spring XML extensions that perfectly integrate Spring, lowering the barriers to use for Dubbo.
In the 2.x era, version 2.5 was also a watershed for this era, introducing some very core annotations
- Autowired dependency injection
- Qualifier depends on lookup
- @Component, @service Component declarations
- Spring MVC annotations for @Controller, @requestMappring, etc
Although Spring 2.x provides a number of annotations, it is still not free from XML configuration drivers, such as Context :annotation-config Context: Componet-Scan, which is responsible for registering annotation processors, The latter is responsible for scanning the classes marked by Spring schema annotations in the specified package path of the classpath and registering them as Spring beans
-
Define context in applicationContext.xml: Componet-scan
<context:component-scan base-package="com.gupaoedu.controller"/> Copy the code
-
Add an annotation statement
@Service public class TestService {}Copy the code
-
The 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); }}Copy the code
Spring Framework 3.x
Spring Framework3.0 was a landmark era, with very large extensions to its features, such as a full embrace of Java5 and Spring annotations. Most importantly, it provides the @configuration class annotation, which appears primarily to replace the XML Configuration method. Unfortunately, Spring Framework3.0 does not introduce an annotation to replace the XML element context:componet-scan. Instead, a transition was chosen, @importResource.
@importResource allows you to import legacy XML configuration files, such as
@ImportResource("classpath:/META-INF/spring/other.xml")
@Configuration
public class SpringConfiguration{}Copy the code
And in the Spring Frameworkd provides AnnotationConfigApplicationContext register to register @ the Configuration Class, by parsing the Configuration Class for assembly.
In version 3.1, @ComponentScan was introduced, replacing the XML element Context: Component-scan. This annotation is a minor upgrade, but it’s a big step forward for Spring in the annotation-driven world. This also demonstrates Spring’s configuration-free support.
Configuration Configuration Demo
-
Configuration is an annotation used by the JavaConfig Configuration class based on the Spring IOC container. Since SpringBoot is essentially a Spring application, it is normal to load the IOC container configuration through this annotation. So the @Configuration tag in the startup class means that it is also a Configuration class for the IoC container.
Let’s take a very simple example
-
The test code
ConfigurationDemo @Configuration public class ConfigurationDemo { @Bean public DemoClass demoClass(a){ return new DemoClass(); } } DemoClass public class DemoClass { public void say(a){ System.out.println("say: Hello Mic"); } } ConfigurationMain public class ConfigurationMain { public static void main(String[] args) { ApplicationContext applicationContext= newAnnotationConfigApplicationContext (ConfigurationDemo.class); DemoClass demoClass=applicationContext.getBean(DemoClass.class); demoClass.say(); }}Copy the code
Component-scan
ComponentScan is the most common annotation, equivalent to context: Component-scan in an XML configuration file. Its main function is to scan the designated path for classes that need to be assembled automatically into Spring’s Ioc container.
Classes that need to be assembled are identified in the form of @Component, @repository, @Service, and @Controller annotations.
-
In the spring-MVC project, create a separate package path and create an OtherServcie.
@Service public class OtherService {}Copy the code
-
In the Controller, you inject an instance of OtherService, and when you access this interface, you get an error saying there is no instance of OtherService.
@RestController public class HelloController { @Autowired OtherService otherService; @GetMapping("/hello") public String hello(a){ System.out.println(otherService); return "Hello Gupaoedu"; }}Copy the code
-
Add conpoment-scan annotation, access again, error resolved.
@ComponentScan("com.gupaoedu") Copy the code
By default, ComponentScan scans all annotated classes in the current package into the IoC container;
The Import annotations
What does an import annotation mean? Think of an annotation in XML form in the form of
-
Create a package and add a separate Configuration to it
public class DefaultBean {}@Configuration public class SpringConfig { @Bean public DefaultBean defaultBean(a){ return newDefaultBean(); }}Copy the code
-
Run the test method at this point,
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); }}}Copy the code
-
Create a configuration class in a different package path. When you run the previous test method again and print an instance of OtherBean, an error is reported indicating that the instance is not present
public class OtherBean {}@Configuration public class OtherConfig { @Bean public OtherBean otherBean(a){ return newOtherBean(); }}Copy the code
-
Modify springConfig to import another configuration
@Import(OtherConfig.class) @Configuration public class SpringConfig { @Bean public DefaultBean defaultBean(a){ return newDefaultBean(); }}Copy the code
-
Run the test method again and see the output of the object instance.
So far, we’ve seen the Spring Framework’s solution to completely replace XML in the annotation-driven era. Is this the end of the Spring team? You guys are too simple. Although configuration-free can reduce the hassle of configuration maintenance, there are still many basic configuration declarations for third-party components. It was also tedious, so Spring retired the @enable module driver. This feature further simplifies the configuration of Spring beans by assembling functional components with the same responsibilities in a modular manner.
Enable Module driver
We use the scheduled task mechanism provided by Spring to implement a scheduled task function. We demonstrate the difference between using the Enable annotation and not using the Enable annotation. Let’s get a feel for some Enable annotations.
Before using EnableScheduing
-
Add the scheduled scheduling configuration to applicationContext.xml
<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> Copy the code
-
Write a task handling class
@Service public class TaskService { @Scheduled(fixedRate = 5000) // The @scheduled method declares that the method is a Scheduled task, executed at fixed intervals using the fixedRate attribute public void reportCurrentTime(a){ System.out.println("Every five seconds."+newDate()); }}Copy the code
-
Writing test classes
public class TestTask { public static void main(String[] args) { ApplicationContext applicationContext=new FileSystemXmlApplicationContext("classpath:applicationContext.xml"); }}Copy the code
After using EnableScheding
-
Create a configuration class
@Configuration @ComponentScan("com.gupaoedu.controller") @EnableScheduling public class SpringConfig {}Copy the code
-
Create a Service
@Service public class TaskService { @Scheduled(fixedRate = 5000) // The @scheduled method declares that the method is a Scheduled task, executed at fixed intervals using the fixedRate attribute public void reportCurrentTime(a){ System.out.println("Every five seconds."+newDate()); }}Copy the code
-
Create a main method
public class TaskMain { public static void main(String[] args) { ApplicationContext context=newAnnotationConfigApplicationContext(SpringConfig.class); }}Copy the code
-
To implement the scheduled scheduling function, start the service.
Which step is omitted by thinking about using Enable?
First let’s look at the code that doesn’t use Enable
<task:annotation-driven scheduler="scheduler"/>
Copy the code
The scheduler is an annotation drive, will be AnnotationDrivenBeanDefinitionParser the parser for parsing.
In the Parse method, the following code is defined
builder = BeanDefinitionBuilder.genericBeanDefinition("org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor");
builder.getRawBeanDefinition().setSource(source);
Copy the code
This class is used to parse @Scheduled annotations.
Ok, we’ll have a look at EnableScheduling annotations, we can see, it will automatically register a ScheduledAnnotationBeanPostProcessor bean. So, in this example, we want to illustrate the use of the Enable annotation, which can help us omit some of the declared configuration of the bean of the third party module.
public class SchedulingConfiguration {
public SchedulingConfiguration(a) {}@Bean( name = {"org.springframework.context.annotation.internalScheduledAnnotationProcessor"} )
@Role(2)
public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor(a) {
return newScheduledAnnotationBeanPostProcessor(); }}Copy the code
Spring Framework 4.x
Spring 4.x version is a perfect era of annotation. It mainly improves Conditional assembly ability by introducing @Conditional annotation, which makes up for the shortcomings of Conditional configuration in previous versions by customizing Condition to realize coordination.
To put it simply, Conditional provides a judgment on the loading condition of a Bean. That is, if the condition is not met, an object declared via @bean will not be automatically loaded. First, let’s briefly take you to understand its basic use.
An overview of Conditional
@Conditional is an annotation, and if we look at the annotation declaration, it can receive an array of conditions.
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}
Copy the code
@FunctionalInterface
public interface Condition {
boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
}
Copy the code
Condition is a functional interface that provides a matchers method. In short, it provides a matching rule that returns true to indicate that beans can be injected and false to indicate that beans cannot be injected.
Conditional ‘
-
If the current operating system is Windows, return true, otherwise return false
public class GpCondition implements Condition{ @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { If true is returned, the configuration class or Bean needs to be loaded // Otherwise, the load is not loaded String os=conditionContext.getEnvironment().getProperty("os.name"); if(os.contains("Windows")) {return true; } return false; }}Copy the code
-
Create a configuration class that loads a BeanClass
@Configuration public class ConditionConfig { @Bean @Conditional(GpCondition.class) public BeanClass beanClass(a){ return newBeanClass(); }}Copy the code
-
Add @Conditional(gpCondition.class) to BeanClass’s bean declaration method, where the specific condition is our custom GpCondition class. What the above code means is that if Matchs in the GpCondition class returns true, the BeanClass is loaded into the Spring IoC container
-
Run test method
public class ConditionMain { public static void main(String[] args) { AnnotationConfigApplicationContext context=newAnnotationConfigApplicationContext(ConditionConfig.class); BeanClass beanClass=context.getBean(BeanClass.class); System.out.println(beanClass); }}Copy the code
conclusion
After an overall analysis of Spring’s annotation drive, it is not difficult to find that the Spring team’s efforts to address user pain points are the reason why we can easily implement a large number of Spring features based on annotations. Spring Boot’s autowiring mechanism is also an evolution of Spring’s annotation driver, and I’ll focus on the autowiring mechanism of Spring Boot in a future article.
Copyright Notice: All articles on this blog are subject to a CC BY-NC-SA 4.0 license unless otherwise stated. Reprint please specify from Mic to take you to learn structure! If this article is helpful to you, please also help to point attention and like, your persistence is the power of my continuous creation. Welcome to pay attention to the same wechat public account for more technical dry goods!