"SpringBoot" Stop asking me how to write Starter

Posted May 27, 20206 min read

1 Introduction

In the past, an interviewer asked me about the development process of SpringBoot Starter. I said that I did n t write a starter, and then I did n t, and the interviewer said that I did n t have enough technical depth.

I want to say that this thing is not very simple, if you want to write one by yourself, it is also a matter of minutes. As for the fact that I haven't written a starter, I think I don't know SpringBoot at all?

Of course, I did not have enough level at that time. I even forgot what the Java SPI was, and then picked it up again. It turned out that I used the Java SPI when I was in college. It's too late to regret it! If you do n t know what SPI is, you can read another article "JVM" Do n t ask me what is parent delegation and SPI

2 What is SpringBoot starter

The starter is an important part of SpringBoot. It is equivalent to an integrated module. For example, you want to use Mybatis and lombok, but you need to write two dependencies in the pom file. If you integrate them as a starter(or more) You need to integrate the dependencies), then you only need to write a starter dependency in the pom file, which is extremely beneficial to the development and maintenance of a reusable module.

At the same time, after the starter dependency is introduced in maven, Spring Boot can automatically scan the information to be loaded and start the corresponding default configuration, which follows the concept of "convention is greater than configuration".

3 How to develop a SpringBoot starter

3.0 Environmental description

  • jdk 1.8.0 \ _151
  • maven 3.6.3
  • IDEA compiler
  • The starter to be developed is a date formatting tool. Its function is to specify how to convert the date type. At the same time, this function can be turned on and off in the configuration file.

3.1 Create a project

Create a new maven project in IDEA, as shown below.

1.png

Spring officially recommends that custom starters use the xxx-spring-boot-starter naming convention to distinguish between starters provided by the SpringBoot ecosystem.

Then you need to add the dependencies needed to implement the starter in the pom file.

<? 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> org.walker.planes </groupId>
    <artifactId> date-format-spring-boot-starter </artifactId>
    <version> 1.0-SNAPSHOT </version>

    <dependencies>
        <dependency>
            <groupId> org.springframework.boot </groupId>
            <artifactId> spring-boot-autoconfigure </artifactId>
            <version> 2.3.0.RELEASE </version>
        </dependency>
    </dependencies>
</project>

3.2 Create configuration information entity class

When developing a Spring Boot project, we sometimes make some configuration changes in the application.properties configuration file to open or modify related configurations, such as server.port can be used to modify the port where the project starts, So when writing a custom date format starter, you can also use this function, according to the configuration file to open or close a function.

We added two new configuration items to the application.properties configuration file. The first one is used to control the starter's startup or shutdown, and the second one is the formatting information that needs to be specified.

Then create a configuration file mapping class, and its private member variable pattern is the attribute that needs to be specified in the configuration file. If it is not specified, the default value is yyyy-MM-dd HH:mm:ss.

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
* Configuration information entity class
* @author Planeswalker23
* @date 2020-05-25
* /
@ConfigurationProperties("formatter")
public class DateFormatProperties {

   /**
     * default format pattern
     * /
    private String pattern = "yyyy-MM-dd HH:mm:ss";

    //Ignore getter setter
}

The function of @ConfigurationProperties(prefix =" formatter ") is to map the configuration information with the same prefix to the entity class through the configuration item name. Here you can map the configuration items prefixed with formatter in the application.properties configuration file to the DateFormatProperties class.

3.3 Create a configuration class

Then we need to create a configuration class that can inject the core function class into the Ioc container, so that the automatic configuration function can be used in other projects that refer to this starter.

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;

import java.text.SimpleDateFormat;

/**
* Configuration information entity class
* @author Planeswalker23
* @date 2020-05-25
* /
@Configuration
@EnableConfigurationProperties(DateFormatProperties.class)
@ConditionalOnProperty(prefix = "formatter", name = "enabled", havingValue = "true")
public class DateFormatConfiguration {
private DateFormatProperties dateFormatProperties;
public DateFormatConfiguration(DateFormatProperties dateFormatProperties) {
this.dateFormatProperties = dateFormatProperties;
}

    @Bean(name = "myDateFormatter")
    public SimpleDateFormat myDateFormatter() {
        System.out.println("start to initialize SimpleDateFormat with pattern:" + dateFormatProperties.getPattern());
        return new SimpleDateFormat(dateFormatProperties.getPattern());
    }
}
  • The function of the starter here is based on the SimpleDateFormat class. In fact, it parses the specified format in the configuration file, sets it as the pattern attribute of SimpleDateFormat, and then registers the SimpleDateFormat class as a "component" in the Ioc container, so that we can refer to it The custom format function is used in the starter project.
  • The role of the @ Configuration annotation is to inject the DateFormatConfiguration class as a configuration class into the container
  • The function of the @ EnableConfigurationProperties annotation is to enable the loading of resource entity classes, which means to enable the function of mapping configuration files to resource entity classes.
  • The @ ConditionalOnProperty annotation is to enable conditional configuration, which means that the starter will only take effect if the value of the formatter.enabled property in the configuration file is true.

3.4 Specify automatic assembly

The business code developed so far is over, but the most important step is to specify the DateFormatConfiguration class as the auto-assembly class.

This requires creating a MATE-INF folder under the resource directory, and creating a file named spring.factories, and then writing in the file

org.springframework.boot.autoconfigure.EnableAutoConfiguration = org.walker.planes.DateFormatConfiguration

The meaning of this line of code is to set DateFormatConfiguration to auto-assembly class. When the SpringBoot project starts, it will scan the spring.factories file in the MATE-INF folder and load the class specified in this file to start the auto-assembly function.

3.5 Release & Test

Then hit the mvn clean install command on the command line. When you see the following output, the customized starter can be referenced as a dependency.

[INFO]----------------------------------------------- ------------
[INFO]BUILD SUCCESS
[INFO]----------------------------------------------- ------------
[INFO]Total time:1.470 s
[INFO]Finished at:2020-05-25T20:24:49 + 08:00
[INFO]----------------------------------------------- ------------

Create a new test project and add the following dependencies to the pom file.

<dependency>
    <groupId> org.walker.planes </groupId>
    <artifactId> date-format-spring-boot-starter </artifactId>
    <version> 1.0-SNAPSHOT </version>
</dependency>

Then open the custom starter configuration in the application.properties file.

formatter.enabled = true
formatter.pattern = yyyy-MM-dd

Then create a Runner task in the startup class and simply output a date class, as shown below.

@SpringBootApplication
public class FirstStarterApplication implements ApplicationRunner {

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

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println(simpleDateFormat.format(new Date()));
    }

    @Resource(type = SimpleDateFormat.class)
    private SimpleDateFormat simpleDateFormat;
}

Starting the project, we can see that the automatic configuration takes effect, and the program overrides the default pattern specified in the configuration file.

  . ____ _ __ _ _
/\\/___'_ __ _ _(_) _ __ __ _ \ \ \ \

(() \ _ | '_ |' _ | | '_ /` | \ \ \
\/
) | | ) | | | | | ||( | |)))))
'| __ | . | _ | | _ | _ | | _ \ , |////
========= | _ | ============== | _
/=///_ /
::Spring Boot ::(v2.3.0.RELEASE)

2020-05-25 20:31:27.144 INFO 5559 --- [main]org.test.FirstStarterApplication:Starting FirstStarterApplication on fandeMac-mini.local with PID 5559(/Users/fan/workspace/first-starter/target/classes started by fan in/Users/fan/workspace/first-starter)
2020-05-25 20:31:27.146 INFO 5559 --- [main]org.test.FirstStarterApplication:No active profile set, falling back to default profiles:default
start to initialize SimpleDateFormat with pattern:yyyy-MM-dd
2020-05-25 20:31:27.792 INFO 5559 --- [main]org.test.FirstStarterApplication:Started FirstStarterApplication in 0.894 seconds(JVM running for 1.4)
2020-05-25

summary

So far, we have completed the development of a simple Spring Boot Start, and finally summarize the development process of a starter.

  1. Introduce spring-boot-autoconfigure dependency
  2. Create a configuration entity class
  3. Create an automatic configuration class, set the instantiation conditions(@Conditionalxxx annotation, can not be set), and inject into the container
  4. Create a spring.factories folder under the MATE-INF folder to activate automatic configuration.
  5. Publish the starter in the maven repository