2-springboot custom configuration process

1. Parent

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.4</version>
</parent>
<!--To view the parent configuration of its parent:-->
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-dependencies</artifactId>
  <version>2.5.4</version>
</parent>
<!--Guess that many dependent configuration items may be configured:-->
<properties>
  <activemq.version>5.16.3</activemq.version>
  <antlr2.version>2.7.7</antlr2.version>
  <appengine-sdk.version>1.9.91</appengine-sdk.version>
  <artemis.version>2.17.0</artemis.version>
  <aspectj.version>1.9.7</aspectj.version>
  <assertj.version>3.19.0</assertj.version>
  <atomikos.version>4.0.6</atomikos.version>
  <awaitility.version>4.0.3</awaitility.version>
  <build-helper-maven-plugin.version>3.2.0</build-helper-maven-plugin.version>
  <byte-buddy.version>1.10.22</byte-buddy.version>
  <caffeine.version>2.9.2</caffeine.version>
  <cassandra-driver.version>4.11.3</cassandra-driver.version>
  <classmate.version>1.5.1</classmate.version>
  <commons-codec.version>1.15</commons-codec.version>
  <commons-dbcp2.version>2.8.0</commons-dbcp2.version>
  <commons-lang3.version>3.12.0</commons-lang3.version>
  <commons-pool.version>1.6</commons-pool.version>
  <commons-pool2.version>2.9.0</commons-pool2.version>
  <couchbase-client.version>3.1.7</couchbase-client.version>
  <db2-jdbc.version>11.5.6.0</db2-jdbc.version>
  <dependency-management-plugin.version>1.0.11.RELEASE</dependency-management-plugin.version>
  <derby.version>10.14.2.0</derby.version>
  <dropwizard-metrics.version>4.1.25</dropwizard-metrics.version>
  <ehcache.version>2.10.9.2</ehcache.version>
  <ehcache3.version>3.9.5</ehcache3.version>
  <elasticsearch.version>7.12.1</elasticsearch.version>
  <embedded-mongo.version>3.0.0</embedded-mongo.version>
  <flyway.version>7.7.3</flyway.version>
  <freemarker.version>2.3.31</freemarker.version>
  <git-commit-id-plugin.version>4.0.5</git-commit-id-plugin.version>
  <glassfish-el.version>3.0.3</glassfish-el.version>
  <glassfish-jaxb.version>2.3.5</glassfish-jaxb.version>
  <groovy.version>3.0.8</groovy.version>
  <gson.version>2.8.7</gson.version>
  <h2.version>1.4.200</h2.version>
  <hamcrest.version>2.2</hamcrest.version>
  <hazelcast.version>4.1.5</hazelcast.version>
  <hazelcast-hibernate5.version>2.2.1</hazelcast-hibernate5.version>
  <hibernate.version>5.4.32.Final</hibernate.version>
  <hibernate-validator.version>6.2.0.Final</hibernate-validator.version>
  <hikaricp.version>4.0.3</hikaricp.version>
  <hsqldb.version>2.5.2</hsqldb.version>
  <htmlunit.version>2.49.1</htmlunit.version>
  <httpasyncclient.version>4.1.4</httpasyncclient.version>
  <httpclient.version>4.5.13</httpclient.version>
  <httpclient5.version>5.0.4</httpclient5.version>
  <httpcore.version>4.4.14</httpcore.version>
  <httpcore5.version>5.1.1</httpcore5.version>
  <infinispan.version>12.1.7.Final</infinispan.version>
  <influxdb-java.version>2.21</influxdb-java.version>
  <jackson-bom.version>2.12.4</jackson-bom.version>
  <jakarta-activation.version>1.2.2</jakarta-activation.version>
  <jakarta-annotation.version>1.3.5</jakarta-annotation.version>
  <jakarta-jms.version>2.0.3</jakarta-jms.version>
  <jakarta-json.version>1.1.6</jakarta-json.version>
  <jakarta-json-bind.version>1.0.2</jakarta-json-bind.version>
  <jakarta-mail.version>1.6.7</jakarta-mail.version>
  <jakarta-persistence.version>2.2.3</jakarta-persistence.version>
  <jakarta-servlet.version>4.0.4</jakarta-servlet.version>
  <jakarta-servlet-jsp-jstl.version>1.2.7</jakarta-servlet-jsp-jstl.version>
  <jakarta-transaction.version>1.3.3</jakarta-transaction.version>
  <jakarta-validation.version>2.0.2</jakarta-validation.version>
  <jakarta-websocket.version>1.1.2</jakarta-websocket.version>
  <jakarta-ws-rs.version>2.1.6</jakarta-ws-rs.version>
  <jakarta-xml-bind.version>2.3.3</jakarta-xml-bind.version>
  <jakarta-xml-soap.version>1.4.2</jakarta-xml-soap.version>
  <jakarta-xml-ws.version>2.3.3</jakarta-xml-ws.version>
  <janino.version>3.1.6</janino.version>
  <javax-activation.version>1.2.0</javax-activation.version>
  <javax-annotation.version>1.3.2</javax-annotation.version>
  <javax-cache.version>1.1.1</javax-cache.version>
  <javax-jaxb.version>2.3.1</javax-jaxb.version>
  <javax-jaxws.version>2.3.1</javax-jaxws.version>
  <javax-jms.version>2.0.1</javax-jms.version>
  <javax-json.version>1.1.4</javax-json.version>
  <javax-jsonb.version>1.0</javax-jsonb.version>
  <javax-mail.version>1.6.2</javax-mail.version>
  <javax-money.version>1.1</javax-money.version>
  <javax-persistence.version>2.2</javax-persistence.version>
  <javax-transaction.version>1.3</javax-transaction.version>
  <javax-validation.version>2.0.1.Final</javax-validation.version>
  <javax-websocket.version>1.1</javax-websocket.version>
  <jaxen.version>1.2.0</jaxen.version>
  <jaybird.version>4.0.3.java8</jaybird.version>
  <jboss-logging.version>3.4.2.Final</jboss-logging.version>
  <jboss-transaction-spi.version>7.6.1.Final</jboss-transaction-spi.version>
  <jdom2.version>2.0.6</jdom2.version>
  <jedis.version>3.6.3</jedis.version>
  <jersey.version>2.33</jersey.version>
  <jetty-el.version>9.0.48</jetty-el.version>
  <jetty-jsp.version>2.2.0.v201112011158</jetty-jsp.version>
  <jetty-reactive-httpclient.version>1.1.10</jetty-reactive-httpclient.version>
  <jetty.version>9.4.43.v20210629</jetty.version>
  <jmustache.version>1.15</jmustache.version>
  <johnzon.version>1.2.14</johnzon.version>
  <jolokia.version>1.6.2</jolokia.version>
  <jooq.version>3.14.13</jooq.version>
  <json-path.version>2.5.0</json-path.version>
  <json-smart.version>2.4.7</json-smart.version>
  <jsonassert.version>1.5.0</jsonassert.version>
  <jstl.version>1.2</jstl.version>
  <jtds.version>1.3.1</jtds.version>
  <junit.version>4.13.2</junit.version>
  <junit-jupiter.version>5.7.2</junit-jupiter.version>
  <kafka.version>2.7.1</kafka.version>
  <kotlin.version>1.5.21</kotlin.version>
  <kotlin-coroutines.version>1.5.1</kotlin-coroutines.version>
  <lettuce.version>6.1.4.RELEASE</lettuce.version>
  <liquibase.version>4.3.5</liquibase.version>
  <log4j2.version>2.14.1</log4j2.version>
  <logback.version>1.2.5</logback.version>
  <lombok.version>1.18.20</lombok.version>
  <mariadb.version>2.7.4</mariadb.version>
  <maven-antrun-plugin.version>1.8</maven-antrun-plugin.version>
  <maven-assembly-plugin.version>3.3.0</maven-assembly-plugin.version>
  <maven-clean-plugin.version>3.1.0</maven-clean-plugin.version>
  <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
  <maven-dependency-plugin.version>3.1.2</maven-dependency-plugin.version>
  <maven-deploy-plugin.version>2.8.2</maven-deploy-plugin.version>
  <maven-enforcer-plugin.version>3.0.0</maven-enforcer-plugin.version>
  <maven-failsafe-plugin.version>2.22.2</maven-failsafe-plugin.version>
  <maven-help-plugin.version>3.2.0</maven-help-plugin.version>
  <maven-install-plugin.version>2.5.2</maven-install-plugin.version>
  <maven-invoker-plugin.version>3.2.2</maven-invoker-plugin.version>
  <maven-jar-plugin.version>3.2.0</maven-jar-plugin.version>
  <maven-javadoc-plugin.version>3.2.0</maven-javadoc-plugin.version>
  <maven-resources-plugin.version>3.2.0</maven-resources-plugin.version>
  <maven-shade-plugin.version>3.2.4</maven-shade-plugin.version>
  <maven-source-plugin.version>3.2.1</maven-source-plugin.version>
  <maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
  <maven-war-plugin.version>3.3.1</maven-war-plugin.version>
  <micrometer.version>1.7.3</micrometer.version>
  <mimepull.version>1.9.15</mimepull.version>
  <mockito.version>3.9.0</mockito.version>
  <mongodb.version>4.2.3</mongodb.version>
  <mssql-jdbc.version>9.2.1.jre8</mssql-jdbc.version>
  <mysql.version>8.0.26</mysql.version>
  <nekohtml.version>1.9.22</nekohtml.version>
  <neo4j-java-driver.version>4.2.7</neo4j-java-driver.version>
  <netty.version>4.1.67.Final</netty.version>
  <netty-tcnative.version>2.0.40.Final</netty-tcnative.version>
  <oauth2-oidc-sdk.version>9.9.1</oauth2-oidc-sdk.version>
  <nimbus-jose-jwt.version>9.10.1</nimbus-jose-jwt.version>
  <ojdbc.version>19.3.0.0</ojdbc.version>
  <okhttp3.version>3.14.9</okhttp3.version>
  <oracle-database.version>21.1.0.0</oracle-database.version>
  <pooled-jms.version>1.2.2</pooled-jms.version>
  <postgresql.version>42.2.23</postgresql.version>
  <prometheus-pushgateway.version>0.10.0</prometheus-pushgateway.version>
  <quartz.version>2.3.2</quartz.version>
  <querydsl.version>4.4.0</querydsl.version>
  <r2dbc-bom.version>Arabba-SR10</r2dbc-bom.version>
  <rabbit-amqp-client.version>5.12.0</rabbit-amqp-client.version>
  <reactive-streams.version>1.0.3</reactive-streams.version>
  <reactor-bom.version>2020.0.10</reactor-bom.version>
  <rest-assured.version>4.3.3</rest-assured.version>
  <rsocket.version>1.1.1</rsocket.version>
  <rxjava.version>1.3.8</rxjava.version>
  <rxjava-adapter.version>1.2.1</rxjava-adapter.version>
  <rxjava2.version>2.2.21</rxjava2.version>
  <saaj-impl.version>1.5.3</saaj-impl.version>
  <selenium.version>3.141.59</selenium.version>
  <selenium-htmlunit.version>2.49.1</selenium-htmlunit.version>
  <sendgrid.version>4.7.4</sendgrid.version>
  <servlet-api.version>4.0.1</servlet-api.version>
  <slf4j.version>1.7.32</slf4j.version>
  <snakeyaml.version>1.28</snakeyaml.version>
  <solr.version>8.8.2</solr.version>
  <spring-amqp.version>2.3.10</spring-amqp.version>
  <spring-batch.version>4.3.3</spring-batch.version>
  <spring-data-bom.version>2021.0.4</spring-data-bom.version>
  <spring-framework.version>5.3.9</spring-framework.version>
  <spring-hateoas.version>1.3.3</spring-hateoas.version>
  <spring-integration.version>5.5.3</spring-integration.version>
  <spring-kafka.version>2.7.6</spring-kafka.version>
  <spring-ldap.version>2.3.4.RELEASE</spring-ldap.version>
  <spring-restdocs.version>2.0.5.RELEASE</spring-restdocs.version>
  <spring-retry.version>1.3.1</spring-retry.version>
  <spring-security.version>5.5.2</spring-security.version>
  <spring-session-bom.version>2021.0.2</spring-session-bom.version>
  <spring-ws.version>3.1.1</spring-ws.version>
  <sqlite-jdbc.version>3.34.0</sqlite-jdbc.version>
  <sun-mail.version>1.6.7</sun-mail.version>
  <thymeleaf.version>3.0.12.RELEASE</thymeleaf.version>
  <thymeleaf-extras-data-attribute.version>2.0.1</thymeleaf-extras-data-attribute.version>
  <thymeleaf-extras-java8time.version>3.0.4.RELEASE</thymeleaf-extras-java8time.version>
  <thymeleaf-extras-springsecurity.version>3.0.4.RELEASE</thymeleaf-extras-springsecurity.version>
  <thymeleaf-layout-dialect.version>2.5.3</thymeleaf-layout-dialect.version>
  <tomcat.version>9.0.52</tomcat.version>
  <unboundid-ldapsdk.version>4.0.14</unboundid-ldapsdk.version>
  <undertow.version>2.2.10.Final</undertow.version>
  <versions-maven-plugin.version>2.8.1</versions-maven-plugin.version>
  <webjars-hal-browser.version>3325375</webjars-hal-browser.version>
  <webjars-locator-core.version>0.46</webjars-locator-core.version>
  <wsdl4j.version>1.6.3</wsdl4j.version>
  <xml-maven-plugin.version>1.0.2</xml-maven-plugin.version>
  <xmlunit2.version>2.8.2</xmlunit2.version>
</properties>

If he really manages all the dependent versions in the Spring Boot application
Spring Boot version Arbitration Center;
In the future, we will import dependency. By default, we don't need to write a version( Dependencies that are not managed in dependencies (naturally, the version number needs to be declared)

2. Starter

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

Spring boot starter: spring boot scenario initiator; Help us import the components that the web module depends on for normal operation;
Spring Boot extracts all functional scenarios and makes them into starters. It only needs to introduce these starters into the project, and all dependencies of related scenarios will be imported. You can import the initiator of any scene with any function you want
View official: All starters
Note: not all initiators are included. For example, mybatis initiators are not included here. If they need to be used, they need to be imported by themselves.
Spring boot starter parent is mainly used for unified version management. So how do you get the jar you depend on? How is it managed?
View the source code of spring boot starter web dependency:

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>2.5.4</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-json</artifactId>
    <version>2.5.4</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <version>2.5.4</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.3.9</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.9</version>
    <scope>compile</scope>
  </dependency>
</dependencies>

It can be found that the role of spring boot starter web dependency launcher is mainly to provide all the underlying dependencies required for web development scenarios. The dependencies required for web development are managed uniformly. Through this dependency, we can guess that its startup is managed in this way. In development, we only need to import the corresponding starter to use the corresponding scenario development.

3.SpringBoot auto configuration

Main program:

@SpringBootApplication
public class HelloWorldApplication {
    public static void main(String[] args) {
        /*application was launched*/
        SpringApplication.run(HelloWorldApplication.class,args);
    }
}

@Springbootapplication: the spring boot application is marked on a class to indicate that this class is the main configuration class of SpringBoot. SpringBoot should run the main method of this class to start the SpringBoot application.
@The main () method in the SpringBootApplication annotation class is the program startup entry. It can scan spring components and automatically configure spring boot. How does it realize automatic configuration?
View source code:

@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 {
....
}

It can be found that * * @ SprinbBootApplication * * is a composite annotation. from
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
It consists of three core annotations.
① View the source code of @ SpringBootConfiguration:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
}

@Source code of Configuration:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
}

From the above source code, we can know that the bottom layer of * * @ SpringBootConfiguration is @ Configuration * *, and the bottom layer of * * @ Configuration is @ Component * *. Then the class marked by * * @ SprinbBootApplication is actually a Configuration class of spring. It is just a Component in the spring container. It's just encapsulated by springboot.
② View the source code of @ EnableAutoConfiguration *:
This annotation indicates that the automatic configuration function is enabled.

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

It is found that it is mainly caused by:

@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})

A combination of two annotations.

@Source code of AutoConfigurationPackage:

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

It is found that the underlying layer is * * @ Import({Registrar.class}) * * which is mainly used to register components in the container:
Registrar source code:

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
    Registrar() {
    }


    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
    }


    public Set<Object> determineImports(AnnotationMetadata metadata) {
        return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
    }
}

Start the project in the Debug mode. You will find that the marked red part obtains the directory where the main program startup class is located. com.qwy. That is, the main function of the * * @ AutoConfigurationPackage * * annotation is to obtain the directory where the main program is located. Specify the location to scan for subsequent component scanners. Therefore, when defining the project package structure, it should comply with the specification: the startup class of the project main program should be defined in the outermost root directory, and other sub packages and classes established within the root directory can be scanned by the scanner.
**@Source code of AutoConfigurationImportSelector class of Import({AutoConfigurationImportSelector.class}) * *:

protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    if (!this.isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    } else {
        AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
        List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
        configurations = this.removeDuplicates(configurations);
        Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
        this.checkExcludedClasses(configurations, exclusions);
        configurations.removeAll(exclusions);
        configurations = this.getConfigurationClassFilter().filter(configurations);
        this.fireAutoConfigurationImportEvents(configurations, exclusions);
        return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
    }
}

getAutoConfigurationEntry() this method is mainly used to filter out the custom configuration class XxxAutoConfiguration that needs to be started in the current project, so as to realize the automatic configuration environment required by the current project.
Main codes in this method:

this.getCandidateConfigurations(annotationMetadata, attributes); This method obtains the auto configuration dependency (META-INF/spring.factories) provided by spring boot and filters out all the auto configuration classes XxxAutoConfiguration (131 in this version)
this.getConfigurationClassFilter().filter(configurations); This method is used to further filter all the above XxxAutoConfiguration, and finally filter the automatic configuration classes that meet the needs of the current project operation according to the dependencies added in the pom.xml file.
META-INF/spring.factories file:

③ The main role of @ ComponentScan
The specific location of the package where the main program parsed by the previous * * @ AutoConfigurationPackage * * annotation * * @ ComponentScan * * is used to automatically assemble the annotation classes in the specified package into the Bean container of spring.

Keywords: Java Spring Spring Boot

Added by CaptainStarbuck on Fri, 03 Sep 2021 02:41:41 +0300