When we learn SpringBoot, we have learned that starter is the core component of SpringBoot. SpringBoot provides us with as complete a package as possible, providing a series of automatic configuration starter plug-ins. Using spring-boot-starter-Web, we only need to add a dependency to the POP.xml configuration file, as opposed to the traditional way of adding many associated SpringMVC configuration files. Spring-boot-starter-web provides us with almost all the default configurations, which greatly reduces the complexity of using the framework. Starter does not need to be configured, even if there are some necessary configurations in the application.properties configuration file. Ok, How come XX. starter can get the properties after I set them to application.properties and then process them? Let’s take a closer look at SpringBoot by writing our custom starter with this question in mind

Objective in this chapter

Customize the starter and automate the configuration through spring-boot-autoconfigure.

Build the project

To create the Starter project, we do not need to create a SpringBoot project. We can create a Maven project to meet our requirements. After creating the project, the pom.xml configuration information is as follows:

<? xml version="1.0" encoding="UTF-8"? > <project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> < modelVersion > 4.0.0 < / modelVersion > < groupId > com. Yuqiyu < / groupId > < artifactId > chapter28 < / artifactId > < version > 1.0.0 < / version > < packaging > jar < / packaging > < properties > <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> < version > 1.5.4. RELEASE < / version > < / dependency > < / dependencies > < project >Copy the code

Our starter doesn’t do any other complex logic writing, so the dependencies here are just spring-boot-autoconfigure. You can add any dependencies to your project during development.

Configure the mapping parameter entity

We asked at the beginning of the article how starter reads the required configuration parameters in the application.properties or application.yml configuration file. So let’s look at how you can get custom configuration information. SpringBoot handles this sort of thing by providing an annotation, @ConfigurationProperties, that maps the regular configuration parameters in the application.properties configuration file to the fields in the entity. However, setter methods need to be provided, and the entity code of the custom configuration parameter is shown as follows:

package com.yuqiyu.chapter28; import org.springframework.boot.context.properties.ConfigurationProperties; / entity mapping configuration file * * * * = = = = = = = = = = = = = = = = = = = = = = = = * Created with IntelliJ IDEA. * User: heng yu young * Date: 2017/7/22 * Time: ahaziah * yards cloud: http://git.oschina.net/jnyqy * ======================== */ @ConfigurationProperties(prefix ="hello") public class HelloProperties {// Message content private String MSG ="HengYu"; // Whether to display message content private Boolean show =true;

    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public boolean isShow() {
        return show;
    }
    public void setShow(boolean show) { this.show = show; }}Copy the code

In the above code, we use the @configurationProperties attribute preffix, which sets the prefix of the read parameter. The entity attributes in the configuration file are hello. MSG, hello.show. If no configuration is configured in the configuration file, the default value is used.

Write custom services

We provide a Service for our custom starter and a method called sayHello to return our configured MSG content. The code looks like this:

package com.yuqiyu.chapter28; / custom business implementation * * * * = = = = = = = = = = = = = = = = = = = = = = = = * Created with IntelliJ IDEA. * User: heng yu young * Date: 2017/7/22 * Time: cloud 22:54 * code: http://git.oschina.net/jnyqy * = = = = = = = = = = = = = = = = = = = = = = = = * / public class HelloService {/ / the message content private String MSG. // Whether to display message content private Boolean show =true;

    public String sayHello()
    {
        return show ? "Hello," + msg : "Hidden";
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public void setShow(boolean show) { this.show = show; }}Copy the code

Our code inside the Service is relatively simple, returning a formatted string based on the property parameters.

Next we start writing the autoconfiguration, which is the core part of the starter and is automatically loaded when the project is started. Of course, there are many detailed configurations

Automatic configuration

Automatic configuration is really just providing validation and initialization of entity beans. Let’s start with the code:

package com.yuqiyu.chapter28; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; / custom starter automation configuration * * * * = = = = = = = = = = = = = = = = = = = = = = = = * Created with IntelliJ IDEA. * User: heng yu young * Date: 2017/7/22 * Time: Code cloud: http://git.oschina.net/jnyqy * = = = = = = = = = = = = = = = = = = = = = = = = * / @ Configuration / / open Configuration @ EnableConfigurationProperties (HelloProperties. Class) / / open using a mapping entity object ConditionalOnClass(helloService.class)// ConditionalOnProperty (prefix =)// ConditionalOnProperty (HelloService)// ConditionalOnProperty (prefix =)// ConditionalOnClass(HelloService"hello"// The configuration prefix Hello value = exists"enabled"// Enable matchIfMissing =truePublic class HelloAutoConfiguration {//application.properties Config file mapping prefix entity object @AutoWired private HelloProperties helloProperties; /** * Initializes the new bean to SpringIoc * @ based on the condition that there is no HelloServicereturnConditionalOnMissingBean(helloService.class)// ConditionalOnMissingBean(helloService.class) Initialize HelloService and add it to SpringIoc Public HelloServicehelloService()
    {
        System.out.println(">>>The HelloService Not Found, Execute Create New Bean.); HelloService helloService = new HelloService(); helloService.setMsg(helloProperties.getMsg()); // Set the message content helloService.setshow (helloProperties.isshow ()); // Set whether to displayreturnhelloService; }}Copy the code

There are many annotation configurations in the automated configuration code that we haven’t used before, so let’s start with the above

@ Configuration: this Configuration need not do more to explain, we have been using the @ EnableConfigurationProperties: This is a comment to enable the use of configuration parameters. The value value is the ClassType where we configure the entity parameter mapping, using the configuration entity as the configuration source.

SpringBoot has conditional annotations built in

The annotations related to @conditionalonxxx need to be systematically explained here, because this is the key to our configuration. According to the name, we can understand it as Xxx condition, of course, its actual meaning is also the same. Conditional annotations are a series of annotations, which will be explained in detail below

@ ConditionalOnBean: when the existence condition of the specified Bean SpringIoc container @ ConditionalOnClass: when the existence condition of the specified Class SpringIoc container @ ConditionalOnExpression: ConditionalOnJava: ConditionalOnJava: ConditionalOnJndi: ConditionalOnMissingBean: ConditionalOnJndi: ConditionalOnMissingBean: ConditionalOnMissingBean When the existence condition of the specified Bean SpringIoc container not @ ConditionalOnMissingClass: when SpringIoc container Class conditions specified does not exist @ ConditionalOnNotWebApplication: The current project is not the conditions of the Web project @ ConditionalOnProperty: specify the attributes for the specified value @ ConditionalOnResource: class path if there is a specified value @ ConditionalOnSingleCandidate: When specifying the Bean in SpringIoc container is only one, or even though there are multiple specify preferred Bean @ ConditionalOnWebApplication: the current project is the condition of the Web project

The above annotations are derived from the metaannotation @conditionality, which creates specific Conditional annotations according to different conditions.

So far we have not finished automatic configuration starter, we need to understand how SpringBoot works before we can complete the subsequent coding.

Starter automation operation principle

There is an annotation @enableAutoConfiguration on @SpringBootApplication to enable automatic configuration. The source code of the annotation is as follows:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.boot.autoconfigure;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({EnableAutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<? >[] exclude() default {}; String[] excludeName() default {}; }Copy the code

The @import annotation is used in the @enableAutoConfiguration annotation to import the configuration. EnableAutoConfigurationImportSelector internal is used SpringFactoriesLoader. LoadFactoryNames method scan has the meta-inf/spring. Factories file j Ar package. The spring-boot-autoconfigure package contains the following spring.factories:

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnClassCondition

# Auto Configureorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ ..... omitCopy the code

As you can see, the configuration structure is in the form of Key=>Value, which is used when multiple values are separated, so we can also use this form in the custom starter. Our purpose is to complete the automatic configuration. So the Key here is we need to use the org. Springframework. Boot. Autoconfigure. EnableAutoConfiguration

Custom spring. Factories

< SRC /main/resource > < SRC /main/resource > < SRC /main/resource > < spring.factories >

Configure the automatic configuration of the custom Starter
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.yuqiyu.chapter28.HelloAutoConfigurationCopy the code

Now that our custom starter has been configured, we need to create a New SpringBoot project to test whether our automatic configuration has taken effect.

Create a test SpringBoot project

Before using the custom starter, you need to Install the Maven Jar as the starter to the local PC. To complete the operation, run the Maven command delivered with the IDEA tool

Steps: On the right -> Maven Projects -> Lifecycle -> Install

The pom.xml configuration file for creating the test project looks like this:

<? xml version="1.0" encoding="UTF-8"? > <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> < modelVersion > 4.0.0 < / modelVersion > < groupId > com. Yuqiyu. Sample < / groupId > < artifactId >test- spring - the boot - starter - hello < / artifactId > < version > 0.0.1 - the SNAPSHOT < / version > < packaging > jar < / packaging > < name >test-spring-boot-starter-hello</name>
    <description>Demo project forSpring Boot</description> <parent> <groupId>org.springframework.boot</groupId> The < artifactId > spring - the boot - starter - parent < / artifactId > < version > 1.5.4. RELEASE < / version > < relativePath / > <! -- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> < project. Reporting. OutputEncoding > utf-8 < / project. Reporting. OutputEncoding > < Java version > 1.8 < / Java version > </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <! Yuqiyu </groupId> <artifactId>chapter28</artifactId> <version>1.0.0</version>  </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId>  </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>Copy the code

We just need to add the dependency to the POM.xml configuration file

Run the test

Before running the project, we open the application.properties configuration file to enable debug mode and view the output log of the automatic configuration. The configuration content is as follows:

# Display debug log information
debug=trueCopy the code

Next we start the project and check the console to see if our HelloAutoConfiguration log output exists. The console output looks like this:

. Omit >>>The HelloService Not Found, Execute Create New Bean...... HelloAutoConfiguration matched: -@conditionalonClass found required class'com.yuqiyu.chapter28.HelloService'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
      - @ConditionalOnProperty (hello.enabled) matched (OnPropertyCondition)

   HelloAutoConfiguration#helloService matched:- @ConditionalOnMissingBean (types: com.yuqiyu.chapter28.HelloService; SearchStrategy: all) did not find any beans (OnBeanCondition) ..... omitCopy the code

From the console you can see that the automation configuration of our custom starter has taken effect and conditional injection of the HelloService entity bean into the SpringIoc container according to @conditionAlonmissingBean (HelloService.class)

Write test controller

Let’s write a simple test controller to see HelloService output a formatted string with no parameters. The controller code looks like this:

package com.yuqiyu.sample.testspringbootstarterhello; import com.yuqiyu.chapter28.HelloService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * HelloService * ======================== * Created with IntelliJ IDEA. 2017/7/23 * Time: 11:42 * Code cloud: http://git.oschina.net/jnyqy * ======================== */ @RestController public class HelloController { @autoWired HelloService HelloService; /** * test access address /hello * @returnFormat string */ @requestMapping (value ="/hello")
    public String sayHello()
    {
        returnhelloService.sayHello(); }}Copy the code

Let’s restart the project, visit the address http://127.0.0.1:8080/hello, interface output content is as follows:

Hello, HengYuCopy the code

The output content of the interface is our default value, then we add hello. MSG, hello. Show configuration parameters in the application.

# Configure the custom starter parameter
hello.msg=HengYu Boy
hello.show=trueCopy the code

Restart the project and access the address again. The output is as follows:

Hello, HengYu BoyCopy the code

Our configuration works, and by now I’m sure you’ve seen why our application.properties profile can be used as a unified configuration entry and can be configured to be used by the corresponding starter.

conclusion

That’s the end of this chapter, which explains how to customize the starter and automate the configuration into the SpringBoot project, but there’s still a lot of magic to dig into.

This chapter code has been uploaded to the code cloud: SpringBoot matching source address: gitee.com/hengboy/spr… SpringCloud source code address: gitee.com/hengboy/spr… SpringBoot can be found in: directory: SpringBoot Learning directory: QueryDSL General Query Framework Learning directory: SpringDataJPA SpringDataJPA Learning Directory Thanks for reading! Welcome to join QQ technical exchange group, common progress.