Spring boot auto configuration principle

Spring boot auto configuration principle

For example, spring boot's auto configuration principle is similar to the restaurant's mechanism. For my favorite fish scout recently, if we compare spring boot to fish scout and dinner to our application, when we come to fish scout for dinner (equivalent to adding @ SpringBootApplication in the application), the waiter will guide us to start ordering on the menu paper (the menu paper is pre-defined, equivalent to spring.factories Documents, predefined It means the automatic configuration information that we can use. Probe fish can match the taste of grilled fish by itself or the taste that the store can match for us directly (the same is true for springboot, such as message middleware, which has many flavors to choose, such as rabbitmq and kafka, depending on the business scenario). We check our favorite dishes (equivalent to in the pom file) Introduce the starter of the required framework), and then decide to place an order (start the spring boot application). I like to eat cauliflower very much. Unfortunately, there is no such auxiliary dish for exploratory fish, but we can prepare it by ourselves and take it with us. When we bake the fish, we can add it and cook it. It's really coquettish operation (this is to add the self-defined automatic configuration, which is more troublesome. We need to encapsulate the starter by ourselves).

It's so easy to use. I've always been curious about how springboot is implemented. Today, I'll follow the source code step by step to understand it.

 

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

We can see that MyApplication is the entry class, and there is a main method in the entry class. This method is actually a standard Java application entry method, which is generally used in the main method SpringApplication.run() to start the entire application. It is worth noting that this entry class is declared with @ SpringBootApplication annotation, which is the core annotation of SpringBoot.

 

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    // slightly
}

In this annotation, the most important thing is @ EnableAutoConfiguration. With such a straightforward name, you can see that it is going to start automatic configuration, and spring boot is going to start to complain, so you can enter the source code of @ EnableAutoConfiguration silently.

 

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    // slightly
}

As you can see, @ import annotation is used in @ EnableAutoConfiguration annotation to complete the import configuration function, while s is used in EnableAutoConfigurationImportSelector pringFactoriesLoader.loadFactoryNames Method scan with META-INF/spring.factories The jar package of the file. The following is the 1.5.8.RELEASE implementation source code:

 

 @Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    }
    try {
          AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                    .loadMetadata(this.beanClassLoader);
          AnnotationAttributes attributes = getAttributes(annotationMetadata);
          //Scan has META-INF/spring.factories jar package of files
          List<String> configurations = getCandidateConfigurations(annotationMetadata,
                    attributes);
          //duplicate removal
          configurations = removeDuplicates(configurations);
          //sort
          configurations = sort(configurations, autoConfigurationMetadata);
           //Delete classes to exclude
         Set<String> exclusions = getExclusions(annotationMetadata, attributes);
         checkExcludedClasses(configurations, exclusions);
         configurations.removeAll(exclusions);
         configurations = filter(configurations, autoConfigurationMetadata);
         fireAutoConfigurationImportEvents(configurations, exclusions);
         return configurations.toArray(new String[configurations.size()]);
    }
    catch (IOException ex) {
        throw new IllegalStateException(ex);
    }
}

 

//load spring.factories realization
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
        AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
            getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
    Assert.notEmpty(configurations,
            "No auto configuration classes found in META-INF/spring.factories. If you "
                      + "are using a custom packaging, make sure that file is correct.");
    return configurations;
}

Any spring boot application will introduce spring boot autoconfigure spring.factories The file is under the package. spring.factories The file is in the form of Key=Value. Multiple values are used and separated. The file defines initialization, listener and other information. The real key that makes the automatic configuration effective is org.springframework.boot.autoconfigure.EnableAutoConfiguration , as follows:

 

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
//ellipsis

The enableautoconfiguration above configures multiple classes, which are related to the auto configuration in Spring Boot. The corresponding class configuration information will be parsed during startup. Each configuration class defines the instantiation configuration of the related bean. It shows which beans can be configured automatically and under what conditions, and instantiates these beans. If we customize a starter, we also need to provide it in the jar package of the starter spring.factories File and configure it org.springframework.boot.autoconfigure.EnableAutoConfiguration Corresponding configuration class. The automatic configuration process of all frameworks is basically the same. Judge whether to introduce the framework, obtain the configuration parameters, and initialize the corresponding components of the framework according to the configuration parameters. Some source codes of the initialization data source are as follows:

 

@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
public class DataSourceAutoConfiguration {

    private static final Log logger = LogFactory
            .getLog(DataSourceAutoConfiguration.class);

    @Bean
    @ConditionalOnMissingBean
    public DataSourceInitializer dataSourceInitializer(DataSourceProperties properties,
            ApplicationContext applicationContext) {
        return new DataSourceInitializer(properties, applicationContext);
    }
    //slightly
}

We can see that there are many annotation configurations in the automatic configuration code that we did not use before, which are described in detail below.

@Configuration: there is no need to explain this configuration. We have been using it
@Enable configuration properties: This is a comment to enable the use of configuration parameters. The value value is the ClassType of the parameter mapping of the configuration entity. The configuration entity is used as the configuration source.
The following is the spring boot built-in condition annotation:
@ConditionalOnBean: when the condition of the specified Bean exists in the SpringIoc container
@ConditionalOnClass: when the condition of the specified Class exists in the SpringIoc container
@ConditionalOnExpression: Based on spiel expression
@ConditionalOnJava: Based on JVM version
@ConditionalOnJndi: finds the specified location when JNDI exists
@ConditionalOnMissingBean: when the condition of the specified Bean does not exist in the SpringIoc container
@ConditionalOnMissingClass: when the condition of the specified Class does not exist in the SpringIoc container
@ConditionalOnNotWebApplication: the current project is not a condition of a Web project
@ConditionalOnProperty: whether the specified property has the specified value
@ConditionalOnResource: whether the class path has the specified value
@ConditionalOnSingleCandidate: when there is only one specified Bean in the SpringIoc container, or there are multiple beans but the preferred Bean is specified
@ConditionalOnWebApplication: the condition that the current project is a Web project
The above annotations are all evolved from the meta annotation @ Conditional. Create the above specific condition annotations according to the unused conditions.

summary

Spring boot's design ideas and concepts are very avant-garde, with more understanding and learning, which can be fully used in work. Spring boot is really a good thing.

Tags: Spring SpringBoot RabbitMQ kafka

Posted on Fri, 19 Jun 2020 07:43:01 -0400 by devinemke