1. What is SpringBoot?

For the Spring framework, we’ve seen a lot of Spring MVC, and Spring. The core of Spring is IOC (Inversion of control for the Spring framework, where Spring is responsible for controlling the life cycle of objects and the relationships between objects) and DI (dependency injection). One of the key points of IOC is to dynamically provide an object with other objects that it needs while the system is running. This is achieved through DI (Dependency Injection). For example, object A needs to operate on the database. In the past, we always had to write code in A to obtain A Connection object. With Spring, we just need to tell Spring that A needs A Connection. These frameworks require a lot of XML configuration, or a lot of cumbersome configuration.

The SpringBoot framework is designed to help developers using the Spring framework quickly and efficiently build application solutions based on the Spirng framework and the Spring ecosystem. It is a best practice under the philosophy of “convention over configuration”. It is therefore a framework that serves the framework, and the scope of the service is to simplify the configuration file.

2. Preliminary understanding of Spring Boot

We can use start.spring. IO

@SpringBootApplication
public class SpringBootStudyApplication {
    public static void main(String[] args) { SpringApplication.run(SpringBootStudyApplication.class, args); }}Copy the code

To show you how this works, we use Spring MVC to build a Web application, and SpringBoot simplifies a lot of the logic that makes it very easy to build a Web project.

Springboot provides the spring-boot-starter-Web automatic assembly module

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
Copy the code

Running MVN Spring-boot :run or directly running the main method under the current project can start a Web application that uses the embedded Tomcat service request, but we do not provide any controller to service the Web request. So accessing any path will return a Default SpringBoot Error page.

So, we can create a Controller to fulfill the request

@RestController
public class HelloController {

    @GetMapping("/say")
    public String sayHello(a){
        return "hello Mic"; }}Copy the code

Visit http://localhost:8080/say you can gain a request results. This completes a very simple Web application. Springboot is a product of convention over configuration, so there are a lot of conventions behind building web applications quickly.

  1. At the project structure level, static files and page templates are stored in subdirectories SRC /main/resources
  2. Automatic embedded Tomcat provides HTTP services as a Web container. By default, port 8080 is used for listening
  3. Automates the necessary components of SpringMVC

3. Four cores of Spring Boot

EnableAutoConfiguration Automatic assembly

Starter operating Actuator Monitoring Spring Boot The Cli provides Spring Boot command line functions for Spring Cloud

So today I’m going to focus on the Enable* annotation

4.Enable* Annotations

Enable means to Enable a function

  • EnableScheduling
  • EnableHystrix
  • EnableAsync
  • EnableAutoConfiguration
  • EnableWebMvc

The Enable host is supposed to be a further improvement on the JavaConfig framework, so that users can use the Spring-related framework without having to configure a lot of code to make it easier to use

For example, the common Enable annotations: EnableWebMvc, which introduces all beans that the MVC framework needs in Spring applications;

For example @enablesCheduling to enable scheduled task support;

Looking at EnableAutoConfiguration, we can see that every annotation that starts with Enable is accompanied by an @import annotation.

5. In-depth analysis of automatic assembly in Spring Boot

In Spring Boot, we have to say one point is autoloader, which is the basis of starter and the core of Spring Boot. What is autoloader? Or what is assembly?

Looking back at the Spring Framework, its core functions are IOC and AOP, and the main function of the IOC container is to manage the life cycle of objects. That is, bean management. We call the process of hosting Bean objects into the Spring Ioc container assembly. What is autowiring? Let’s take our time with the introduction

First of all, let’s look at this picture. We won’t explain it. When we’re done with today’s content, we’ll come back to this picture to conclude

Automatic assembly in SpringBoot is based on EnableAutoConfiguration. So before we dive into EnableAutoConfiguration, let’s look at the traditional assembly.

5.1 Simple Analysis @Configuration

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.

public class DemoClass {

    public void say(a){
        System.out.println("sya hello ... "); }}Copy the code
@Configuration
@Import(UserClass.class)
public class DemoConfiguration {

    @Bean
    public DemoClass getDemoClass(a){
        return newDemoClass(); }}Copy the code
public class DemoConfigurationMain {

    public static void main(String[] args) {
        ApplicationContext ac = newAnnotationConfigApplicationContext(DemoConfiguration.class); DemoClass bean = ac.getBean(DemoClass.class); bean.say(); }}Copy the code

This form implements the IoC container through annotations. Traditionally, Spring applications configure bean dependencies based on XML. The beans are then initialized at startup by the Spring container and, if there are dependencies between beans, analyzed and assembled according to those dependencies already in the IoC container.

Until Java5 introduced the Annotations feature, the Spring framework jumped on the bandwagon and introduced a way to describe dependency bindings based on Java code and Annotation meta-information. JavaConfig.

Since Spring 3, spring has supported two ways to configure beans, one based on XML files and the other on JavaConfig

The nature of the Configuration

If you will find more careful Configuration annotation is the essence of a Component annotations, the annotations are AnnotationConfigApplicationContext load, And AnnotationConfigApplicationContext is a concrete realization of ApplicationContext, said according to the configuration comments to start the application context. So we are going to load in the Main method through AnnotationConfigApplicationContext JavaConfig, can get the instance of the bean in the Ioc container JavaConfig way has been demonstrated in the previous code, Any Java class definition labeled @Configuration is a JavaConfig Configuration class. In this configuration class, the return value of any method labeled @bean is registered with Spring’s IOC container as the Bean definition, and the method name defaults to the Bean ID

5.2 Simple Analysis @ComponentScan

ComponentScan is the most frequently encountered 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.

public static void main(String[] args) {
    ApplicationContext ac = new AnnotationConfigApplicationContext(DemoConfiguration.class);
    String[] beanDefinitionNames = ac.getBeanDefinitionNames();
    System.out.println("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
    for(String beanName:beanDefinitionNames ) { System.out.println(beanName); }}Copy the code

5.3 the Import annotations

What does an import annotation mean? Think of an annotation in XML form in the form of
. Import is the merging of multiple container configurations into one configuration. The meaning expressed in JavaConfig is the same. In order to better understand the EnableAutoConfiguration, we will introduce the use of import annotations in detail

Method 1: Directly fill in the class array

Let’s start by creating the corresponding beans under two different packages. Such as:The code executed in DemoConfigurationMain should not load the UserClass in Demo2We can load it directly with @import

or

Method 2 :ImportSelector method

The first way is if you’re importing a configuration class, then everything in that configuration class is going to load, and if you want to be a little bit more flexible and load dynamically you can use the second way of using the Import interface, which is ImportSelector, so let’s see how that works. LogService

public class LogService {}Copy the code

CacheService

public class CacheService {}Copy the code

GpDefineImportSelector

public class GpDefineImportSelector implements ImportSelector {
    /** * AnnotationMetadata AnnotationMetadata *@param annotationMetadata
     * @return* The bean information to be loaded by the IOC container */
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // We can dynamically return loaded bean information based on annotation metadata information
        annotationMetadata
                .getAllAnnotationAttributes(EnableDefineService.class.getName(),true)
        .forEach((k,v)->{
            System.out.println(annotationMetadata.getClassName());
            System.out.println("- >" + k+":" + String.valueOf(v));
        });

        return newString[]{CacheService.class.getName()}; }}Copy the code

EnableDefineService

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(GpDefineImportSelector.class)
public @interface EnableDefineService {

    String[] packages() default "";

}
Copy the code

EnableDemoTest

@EnableDefineService()
@SpringBootApplication
public class EnableDemoTest {

    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(EnableDemoTest.class);//SpringApplication.run(EnableDemoTest.class,args);System.out.println(ac.getBean(CacheService.class)); System.out.println(ac.getBean(LogService.class)); }}Copy the code

The third way: ImportBeanDefinitionRegistrar way

This approach is similar to the second option, the same to achieve ImportBeanDefinitionRegistrar interface

public class GpImportDefinitionRegister implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        // Specify the bean definition information
        RootBeanDefinition beanDefinition = new RootBeanDefinition(CacheService.class);
        RootBeanDefinition beanDefinition1 = new RootBeanDefinition(LogService.class);
        // Register a bean
        beanDefinitionRegistry.registerBeanDefinition("cacheService1111",beanDefinition);
        beanDefinitionRegistry.registerBeanDefinition("cacheService2222",beanDefinition1); }}Copy the code

5.4 In-depth Analysis of EnableAutoConfiguration

To understand theImportSelectorandImportBeanDefinitionRegistrarLater, forEnableAutoConfigurationUnderstanding of the easier it will be through the import import third party bean configuration class: AutoConfigurationImportSelector AutoConfigurationImportSelector

public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!this.isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    } else {
        try {
// Load metadata information in meta-INF /spring-autoconfigure-metadata.properties

            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
// Get the configuration information for the candidate load meta-inf /spring.factories
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
// Delete the duplicate configuration information
            configurations = this.removeDuplicates(configurations);
/ / sorting
            configurations = this.sort(configurations, autoConfigurationMetadata);
            // Get the exclusion information configured in the annotations
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
/ / check
            this.checkExcludedClasses(configurations, exclusions);
// Remove information that needs to be excluded
            configurations.removeAll(exclusions);
ConditionalOnClass = ConditionalOnClass = ConditionalOnClass = ConditionalOnClass = ConditionalOnClass = ConditionalOnClass = ConditionalOnClass = ConditionalOnClass = ConditionalOnClass = ConditionalOnClass
            configurations = this.filter(configurations, autoConfigurationMetadata);
// Broadcast events
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            // Returns an array of classes to be loaded
return (String[])configurations.toArray(new String[configurations.size()]);
        } catch (IOException var6) {
            throw newIllegalStateException(var6); }}}Copy the code

In essence, EnableAutoConfiguration helps the SpringBoot application load all @Configuration configurations into the IoC container created by the current SpringBoot application. This is supported by the SpringFactoriesLoader, a utility class provided by the Spring framework. The Conditional annotation @Conditional provided by Spring is used to selectively filter the beans that need to be loaded

5.5 SpringFactoriesLoader

In order to give you a foundation, I will briefly analyze the use of the SpringFactoriesLoader utility class. It works the same way as SPI in Java, except that it is better than SPI in that instead of loading all classes at once, it loads them by key.

First, the SpringFactoriesLoader loads the corresponding classes according to the key from the classpath/ meta-INF /spring.factories file into the Spring IoC container. Next take you to practice through myBatis integration to see the introduction of MyBatis dependency

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.2</version>
</dependency>
Copy the code

Check MybatisAutoConfiguration inside the source, found in which loaded SqlSessionFactory information.

Through actual cases to achieve

Create a new Maven project to introduce related dependencies

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.6. RELEASE</version>
    </dependency>
</dependencies>
Copy the code

Create a bean class

public class GpCoreService {

    public void crudService(a){
        System.out.println("gupao core service run ..."); }}Copy the code

And the corresponding configuration class

@Configuration
public class GpConfiguration {

    @Bean
    public GpCoreService gpCoreService(a){
        return newGpCoreService(); }}Copy the code

And then packagedImport the JAR package in another project

<dependency>
    <groupId>org.gupao.edu</groupId>
    <artifactId>Gp-Core</artifactId>
    <version>1.0 the SNAPSHOT</version>
</dependency>
Copy the code

Get the properties in the dependency package using the following code

The result is an error because GuPaoCore is not loaded by Spring’s IoC container, that is, it is not imported by EnableAutoConfiguration

public static void main(String[] args) {
    ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
    String[] beanDefinitionNames = run.getBeanDefinitionNames();
    System.out.println(run.getBean(GpCoreService.class));
}
Copy the code

The solution

“Spring. factories” (key: EnableAutoConfiguration) Value is the full path of the configuration class

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.gupao.edu.GpConfiguration
Copy the code

Repack, rerun the SpringBootStudyApplication this class. And you can see that the class that we wrote is loaded in.

5.6 In-depth understanding of conditional filtering

Source code, the analysis of the AutoConfigurationImportSelector will scan the spring – autoconfiguration – metadata. The properties files, last spring in scanning. The corresponding class factories, Will be combined with the previous metadata to filter, why filter? The reason is that a lot of @Configuration is actually loaded from other frameworks, and if there are no dependencies associated with it in the current classpath environment, it means that these classes don’t need to be loaded, so, This condition filtering can effectively reduce the number of @Configuration classes and thus reduce the startup time of SpringBoot. Modify Gupao – Core

Add the configuration file in meta-INF /, spring-autoconfigure-metadata.properties.

com.gupao.edu.GpConfiguration.ConditionalOnClass=com.gupao.edu.service.GpTestService
Copy the code

Format: The full name of the auto-configured class. Conditions = value

If TestClass exists in the current classpath, the GuPaoConfig Configuration will be spring-boot.

1. Following the previous test case of spring-boot project, directly run the main method and find that the GuPaoCore that could be loaded could not be found in the IOC container. 2. After creating a TestClass under the package com.gupaoedu specified in the current project, run the above code, and the program can run normally

Well ~ to this if follow a piece of work, I believe you should have a different understanding of SpringBoot automatic assembly, welcome to the question of message exchange!

The latest video has been recorded, scan code for free! Note: the CSDN