Spring Boot automatic assembly (a)

table of Contents

Foreword

        Recent related courses, recorded during the Spring Boot learning in the form of notes down for easy recall later, at the same time we are here and we explore to explore, article or have tainted supplement, false hope that we can promptly raised , I thank you in advance!

Before you start it, I hope to learn with a few questions:
1. What Spring annotation drivers are?
2, this feature in what the background of the invention produced?
3, What's with this?
4, how to achieve?
5. What are the advantages and disadvantages?
6, this feature can be applied at work?
It is a question of self, I think the problem with to learn, is a better way to learn, contribute to understand. Well, then into the theme.

1, origin

        We first take a brief talk about the history of the Spring annotations. Spring1.x times, when the concept notes is just emerging, such as @Transactional only support and other annotations. Spring 2.x era to have a prototype annotation system, introduced @Autowired, @Controller skeleton of this series of notes. 3.x was the golden age, which in addition to the introduction of @Enable drive module concept, to speed up the molding Spring annotation system, also introduced @Configuration class configuration and @ComponentScan, so that we can abandon the form of an XML configuration file, to embrace Spring Annotations, but did not completely abandon the Spring XML configuration file, which provides @ImportResource allowed to import legacy XML configuration file. @Import also provided to allow introducing one or more Java classes become Spring Bean. 4.X then tend to improve the conditions for the introduction of notes @Conditional, makes assembly more flexible. 5.X is present era, the underlying core framework SpringBoot2.0 the present situation, the change is not great, but it also introduces a @Indexed notes, is mainly used to improve the startup performance. Well, that is the history of Spring annotations, then we explain several issues Spring annotation system.

2, Spring annotation mode

        
Notes is a model for the statement notes to play the role of "components" in the application. As in Spring @Repository for warehousing role to play notes mode, used to manage and store certain areas of the object. There are common components such as @Component mode, @ Service is a service model, @ Configuration mode is configured.
Wherein @Component hosted by the Spring as a common mode component container, any labeled component is @Component assembly candidates are scanned. Similarly, those who have been marked @Component annotations, such as @Service, when any component labels it is also regarded as a candidate scan assembly.
For example:

Spring Annotations Scene Description Starting version
@Componnt General Assembly Mode Notes 2.5
@Repository Data Warehousing mode Notes 2.0
@Service Notes service model 2.5
@Controller Web controller mode Notes 2.5
@Configuration Class configuration mode Notes 3.0

So, how are these notes marked classes handed over to Spring to manage it, or how it was assembled Spring? Next we will look at two assembly methods of Spring.

2.1, assembly methods

  • <Context: component-scan> manner
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd ">

    <context:component-scan base-package="com.loong.spring.boot" />
</beans>

The first is the way XML configuration file, specify the scan all @Component or its derived class annotation marks (Class) within a certain range by base-package this property, they will be registered as a Spring Bean.

We all know that the XML Schema specification, the label needs to be associated explicitly namespace, such as the configuration file
xmlns: context = "http://www.springframework.org/schema/context", and the need to establish the mapping process and its class, this relationship is maintained with respect to the classpath /META-INF/spring.handlers file. as follows:

http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler

See, context corresponding processor ContextNamespaceHandler

public class ContextNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        .....
        registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
        registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
        .....
    }
}

When Spring starts here, init method is called, then all registered Bean parser defined in this namespace, you can see The parser is ComponentScanBeanDefinitionParser. Specific processes in this class, interested students can go to understand, will not repeat them here.

  • @ComponentScan way
@ComponentScan(basePackages = "com.loong.spring.boot")
public class SpringConfiguration {

}

The second is a comment form, is also relying on basePackages attribute specifies the scan range.

Spring at startup, created within a certain life cycle of all configuration parser class notes, and @ComponentScan processor is ComponentScanAnnotationParser, interested students can go to understand, will not repeat them here as well.

2.2 Derivation

We use custom annotation way to look Derivation mentioned in the text:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repository
public @interface FirstLevelRepository {
    String value() default "";
} 

We can see from the definition of a
@FirstLevelRepository notes, annotation and mark the current @Repository, and @Repository has marked @Component and consistent annotation attributes (String value () default "" ), then you can represent the current annotation contains
@Repository and @Component function.

Derivation fact, can be divided into multiple levels, such as
@SprintBootApplication -> @SpringBootConfiguration -> @Configuration - > @Component
can see @Component be derived a number of levels, but this multi-level derivative of Spring 4.0 version began support, Spring3.0 support only two layers.

3, Spring @Enable drive module

        Previously mentioned Spring3.X is a golden age, it is not only to embrace the annotation mode, also began to support "@Enable module driver." The so-called "module" refers to the functional components have the same field of collection, a single unit formed by combining, such as Web MVC modules, the AspectJ proxy module, the Caching (cache) block, JMX (Java Management Extensions) module, the Async (asynchronous processing ) module. This "module" concept have been used in the subsequent Spring, Spring Boot and Spring Cloud version, this modular notes are @Enable as a prefix, as shown below:

Framework implementation @Enable comment module Activation module
Spring Framework @EnableWebMvc Web Mvc module
/ @EnableTransactionManagement Things Management Module
/ @EnableWebFlux Web Flux module
Spring Boot @EnableAutoConfiguration Automatic assembly module
/ @EnableConfigurationProperties Binding module configuration properties
/ @EnableOAuth2Sso OAuth2 single sign-on module
Spring Cloud @EnableEurekaServer Eureka Server Module
/ @EnableFeignClients Feign client module
/ @EnableZuulProxy Zuul service gateway module
/ @EnableCircuitBreaker Services blown module

Significance is to simplify the introduction of the drive module assembly step details screen module component collection assembly. However, the model must be manually triggered, that is, in the notes marked a configuration Bean while understanding the principles of higher costs and loading mechanisms. Well, Spring is how to achieve @Enable module it? There are two main ways.

3.1, Spring Framework implementation @Enable

  • Based on annotation-driven
    First, referring to @EnableWebMvc implementation:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
    
}

@Configuration 
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
    ... 
}

This implementation pattern is mainly import configuration class DelegatingWebMvcConfiguration by @Import, and that class marked @Configuration notes, that this is a configuration class, we all know @EnableWebMvc is used to activate Web MVC module, so as HandlerMapping
, HandlerAdapter these and MVC related components are assembled in this configuration category, which is the so-called modular concept.

  • Based Programming Interface

There are two ways to achieve the same interface-based programming, a first reference @EnableCaching of:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CachingConfigurationSelector.class) 
public @interface EnableCaching {
    ...
}

public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching> {
    
    @Override
    public String[] selectImports(AdviceMode adviceMode) {
        switch (adviceMode) { //switch语句选择实现模式
            case PROXY:
                return new String[]{AutoProxyRegistrar.class.getName(), ProxyCachingConfiguration.class.getName()};
            case ASPECTJ:
                return new String[]{AnnotationConfigUtils.CACHE_ASPECT_CONFIGURATION_CLASS_NAME};
            default:
        }
    }
}

In this way the interface is mainly inherited ImportSelector (AdviceModeImportSelector ImportSelector implements interface), and then implement selectImports method, by introducing into the reference dynamic further select one or more classes, compared to driving annotation, this method is more flexible.

The second reference @EnableApolloConfig implementation:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(ApolloConfigRegistrar.class)
public @interface EnableApolloConfig {
    ....
}
public class ApolloConfigRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        ....

        BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesPlaceholderConfigurer.class.getName(),
        PropertySourcesPlaceholderConfigurer.class, propertySourcesPlaceholderPropertyValues);

        BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesProcessor.class.getName(),
        PropertySourcesProcessor.class);

        BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloAnnotationProcessor.class.getName(),
        ApolloAnnotationProcessor.class);

        BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueProcessor.class.getName(), SpringValueProcessor.class);
        BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueDefinitionProcessor.class.getName(), SpringValueDefinitionProcessor.class);

        BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloJsonValueProcessor.class.getName(),
            ApolloJsonValueProcessor.class);
    }
}

That approach classes that implement the interface ImportBeanDefinitionRegistrar @Import by introducing, in the assembly methods such registerBeanDefinitions override by direct manual BeanDefinitionRegistry register and the related modules.
Next, we realize @Enable custom module with both.

3.2, a custom module for @Enable

  • Based on annotation-driven
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(HelloWorldConfiguration.class)
public @interface EnableHelloWorld {
}
@Configuration
public class HelloWorldConfiguration {

    // 可以做一些组件初始化的操作。

    @Bean
    public String helloWorld(){ 
        return "hello world";
    }
    // ....
}
@EnableHelloWorld
public class EnableHelloWorldBootstrap {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableHelloWorldBootstrap.class)
                .web(WebApplicationType.NONE).run(args);
        String helloWorld = context.getBean("helloWorld",String.class);
        System.out.println(helloWorld );
    }
}

Here we customized a @EnableHelloWorld comment, and then @Import import a self-configuring class HelloWorldConfiguration defined initialization helloWorld in this configuration class.

  • Based Programming Interface
    The first is based ImportSelector Interface:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(HelloWorldImportSelector.class)
public @interface EnableHelloWorld {
}
public class HelloWorldImportSelector implements ImportSelector {
    /**
     * 这种方法比较有弹性:
     *  可以调用importingClassMetadata里的方法来进行条件过滤
     *  具体哪些方法参考:https://blog.csdn.net/f641385712/article/details/88765470
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        if (importingClassMetadata.hasAnnotation("com.loong.case3.spring.annotation.EnableHelloWorld")) {
           return new String[]{HelloWorldConfiguration.class.getName()};
        }
    }
}
@Configuration
public class HelloWorldConfiguration {
    // 可以做一些组件初始化的操作

    @Bean
    public String helloWorld(){ 
        return "hello world";
    }
    // ....
}
@EnableHelloWorld
public class EnableHelloWorldBootstrap {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableHelloWorldBootstrap.class)
                .web(WebApplicationType.NONE).run(args);
        String helloWorld = context.getBean("helloWorld",String.class);
        System.out.println(helloWorld );
    }
}

Here we also @EnableHelloWorld custom annotations, by introducing HelloWorldImportSelector @Import class, which implements the ImportSelector interface in the process of rewriting by importingClassMetadata.hasAnnotation ( "com.loong.case3.spring.annotation.EnableHelloWorld") Analyzing whether the class marked @EnableHelloWorld annotations, import HelloWorldConfiguration class that initializes.

The second on ImportBeanDefinitionRegistrar Interface:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(HelloWorldRegistrar.class)
public @interface EnableHelloWorld {
}
public class HelloWorldRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        if (annotationMetadata.hasAnnotation("com.loong..case4.spring.annotation.EnableHelloWorld")) {
            RootBeanDefinition beanDefinition = new RootBeanDefinition(HelloWorldConfiguration.class);
            beanDefinitionRegistry.registerBeanDefinition(HelloWorldConfiguration.class.getName(), beanDefinition);
        }
    }
}
@Configuration
public class HelloWorldConfiguration {
    public HelloWorldConfiguration() {
        System.out.println("HelloWorldConfiguration初始化....");
    }
}
@EnableHelloWorld
public class EnableHelloWorldBootstrap {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableHelloWorldBootstrap.class)
                .web(WebApplicationType.NONE).run(args);
    }
}

Here is the direct registration HelloWorldConfiguration use BeanDefinitionRegistry in HelloWorldRegistrar in.

4, Spring Assembly conditions

        Refers to a condition of the assembly by assembling a series operation determines whether Bean, i.e. pre-determined Bean assembly. There are two main ways to achieve: @Profile and @Conditional, here we talk about implementation @Conditional because @Profile also be achieved by @Conditional after Spring 4.0.

@Conditional(HelloWorldCondition.class)
@Component
public class HelloWorldConfiguration {
    public HelloWorldConditionConfiguration (){
        System.out.println("HelloWorldConfiguration初始化。。。");
    }
}
public class HelloWorldCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        // ...
        return true;
    }
}

Here HelloWorldConfiguration a custom configuration class, then the class label @Conditional HelloWorldCondition import annotations, Condition class must implement the interface, then override matches method, can be acquired in a series of process context data and metadata through the two parameters eventually return ture or false to determine whether the class initialization,

5, summary

        Concept of annotation-driven Spring came to an end, at last to briefly review the contents of this article, this article is mainly about the Spring annotation-related concepts: Spring pattern annotation, @ Enable drive module assembly and Spring terms.
Spring annotation mode in which the core is @Component, all of which are marked annotation mode, and the corresponding two kinds of assembly methods actually looking @Component process. Spring @Enable module core is introduced via configuration classes @Import on @Enable annotation, and related components in order to achieve this initialization module in the configuration class.
You can see, Spring component assembly does not have the automation, you need to manually mark multiple annotations, and between the need to cooperate with each other, so the next chapter we will say something about how the Spring Boot Spring annotation-based drive to achieve automatic assembly.

These are the contents of this chapter, such as over or there is an error in the article should be added please put forward, I am grateful.



reference:

"Spring Boot programming ideas"

Guess you like

Origin www.cnblogs.com/loongk/p/11970246.html