Do you really know the past and present lives of Spring annotation driven? This article makes you suddenly enlightened!

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 is still not separated from the XML configuration driver. For example, 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

  • Defined 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 XML elements, 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 XML elements. 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 the annotation 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 official account official account of "Mic learning architecture" to get more dry cargo!

Tags: Spring

Posted on Thu, 25 Nov 2021 00:40:08 -0500 by pets2soul