Welcome to wechat public account: “Java words” technical articles continue to update, please continue to follow……

  • Learn the latest technical articles as soon as possible
  • Get the latest technology learning materials video
  • Latest Internet information and interview experience

What is a Starter?

Everyone must have used SpringBoot, in the SpringBoot project, the most used is nothing more than a variety of Starter. What is a Starter? You can think of it as a plug-in. Or a scenario initiator.

Starter can simplify complex configurations without requiring too many configurations and dependencies. It helps you merge dependencies and integrate them into a single Starter. You just need to introduce the Starter dependencies in Maven or Gradle. SpringBoot automatically scans for information that needs to be loaded and starts the corresponding default configuration. For example, if you want to use the JDBC plug-in, you can simply introduce spring-boot-starter-JDBC; If you want to use mongodb, you just need to introduce the spring-boot-starter-data-mongodb dependency.

SpringBoot officially provides a large number of spring-boot-starter dependency modules for daily enterprise application development scenarios. These dependency modules follow the conventions of default configurations and allow us to adjust these configurations to suit our own needs.

In summary, Starter provides the following features:

  • All dependencies required by the module are integrated into Starter.
  • Default configurations are provided and allow us to adjust them.
  • Automatic configuration classes are provided to automate the assembly of beans within the module and inject them into the Spring container.

Starter naming rule

An official Spring Starter is named in the following format: spring-boot-starter-{name}, for example, spring-boot-starter-data-mongodb. Spring recommends that the unofficial Starter be named in the {name}-spring-boot-starter format, for example, myjson-spring-boot-starter.

Customize a Starter

After understanding the meaning and application scenarios of Starter, we can try to write a Starter to deepen our understanding of it and develop our own Starter in practical work to improve our development efficiency.

One might ask, what does Starter do? In fact, in our daily development work, there are always some configuration modules independent of the business system, which can be reused in different projects. If you write repetitive module code in every project, it is not only a waste of time and effort, but also coupled to the project. Therefore, we packaged these functional configuration modules that can be independent of business code into a Starter. In the project that needs to use this functional module, we only need to reference the dependency in its POP.xml file. SpringBoot helps us complete automatic assembly. You can also adjust the default configuration information in Starter in the configuration file.

Suppose we now need to implement a feature like this:

  1. Converts the user-supplied Java object to JSON form and adds the specified prefix and dropout to the JSON string.
  2. Users can dynamically change the dropouts, which can be customized in the YML or Properties profile.

For example, suppose the user enters an object of the following class person:

public class Person {
    private String name;
    private int age;
    private String address;
    public Person(String name, int age, String address) {
        super(a);this.name = name;
        this.age = age;
        this.address = address;
    }
    // omit the get and set methods
}
Copy the code
Person person = new Person("Mr.nobody".18.Las Vegas);
Copy the code

And assuming that the prefix configured by the user in the application.yml configuration file is @ and %, the resulting string is:

@{"address":" Las Vegas ","age":18,"name":"Mr. Nobody "}%Copy the code

Start with a new Maven project (or other types such as Gradle project) and introduce the following dependencies in the POM.xml file. The FastJSON dependency is used by our business to convert Java objects into JSON strings; The spring-boot-configuration-processor dependency is optional. When adding this dependency, the configuration meta-inf /spring-configuration-metadata.json file is automatically generated. And put it into the JAR. This helps users learn about configuration meta information.


      
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.nobody</groupId>
	<artifactId>myjson-spring-boot-starter</artifactId>
	<version>0.0.1 - the SNAPSHOT</version>
	<name>myjson-spring-boot-starter</name>
	<description>Demo project for Spring Boot Starter</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
			<version>2.3.8. RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<version>2.3.8. RELEASE</version>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.73</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-autoconfigure</artifactId>
			<version>2.3.8. RELEASE</version>
		</dependency>
	</dependencies>
</project>
Copy the code

Business processing class that converts Java objects to JSON strings with a specified prefix or suffix.

package com.nobody.myjson.service;

import com.alibaba.fastjson.JSON;

/ * * *@DescriptionBusiness processing class *@Author Mr.nobody
 * @Date 2021/2/27
 * @Version1.0 * /
public class MyJsonService {
    / / prefix
    private String prefixName;
    / / the suffix
    private String suffixName;

    /** * Converts a Java object to a JSON string ** with the specified prefix and suffix@paramO Java objects to be converted *@returnThe converted string */
    public String objectToMyJson(Object o) {
        return prefixName + JSON.toJSONString(o) + suffixName;
    }

    public String getPrefixName(a) {
        return prefixName;
    }

    public void setPrefixName(String prefixName) {
        this.prefixName = prefixName;
    }

    public String getSuffixName(a) {
        return suffixName;
    }

    public void setSuffixName(String suffixName) {
        this.suffixName = suffixName; }}Copy the code

Configuration class: defines required configuration information and default configuration items, and specifies the prefix of the configuration item in the associated configuration file. It maps configuration information with the same prefix through the configuration item name into attributes of the entity class.

package com.nobody.myjson.config;

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

/ * * *@DescriptionConfiguration class (the class name is usually the module name +Properties) nod. json specifies the prefix * of the variable name used by the Starter user to dynamically modify the property value through the YML configuration file@Author Mr.nobody
 * @Date 2021/2/27
 * @Version1.0 * /
@ConfigurationProperties(prefix = "nobody.json")
public class MyJsonProperties {

    Starter Default value if the user does not configure the value of the prefixName property in the configuration file
    public static final String DEFAULT_PREFIX_NAME = "@";

    Starter Default value when the user does not configure the suffixName property value in the configuration file
    public static final String DEFAULT_SUFFIX_NAME = "@";

    private String prefixName = DEFAULT_PREFIX_NAME;

    private String suffixName = DEFAULT_SUFFIX_NAME;

    public String getPrefixName(a) {
        return prefixName;
    }

    public void setPrefixName(String prefixName) {
        this.prefixName = prefixName;
    }

    public String getSuffixName(a) {
        return suffixName;
    }

    public void setSuffixName(String suffixName) {
        this.suffixName = suffixName; }}Copy the code

The autowiring classes, using @Configuration and @Bean for autowiring, are injected into the Spring container.

package com.nobody.myjson.config;

import com.nobody.myjson.service.MyJsonService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/ * * *@DescriptionAutomatic assembly class *@Author Mr.nobody
 * @Date 2021/2/27
 * @Version1.0 * /
@Configuration // Identifies this class as a configuration class
@ConditionalOnClass(MyJsonService.class) // Indicates that the specified class can only be registered if it is on the classpath
@EnableConfigurationProperties(MyJsonProperties.class) / / @ ConfigurationProperties activation
public class MyJsonConfiguration {

    private MyJsonProperties myJsonProperties;

    // Automatically inject configuration classes
    public MyJsonConfiguration(MyJsonProperties myJsonProperties) {
        this.myJsonProperties = myJsonProperties;
    }

    // Create MyJsonService object and inject it into the Spring container
    @Bean
    @ConditionalOnMissingBean(MyJsonService.class) // Only register when the container does not have this bean
    public MyJsonService myJsonService(a) {
        MyJsonService myJsonService = new MyJsonService();
        myJsonService.setPrefixName(myJsonProperties.getPrefixName());
        myJsonService.setSuffixName(myJsonProperties.getSuffixName());
        returnmyJsonService; }}Copy the code

Create a new Spring. factories file in the SRC /main/resources/ meta-INF directory and enter the following:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.nobody.myjson.config.MyJsonConfiguration
Copy the code

When the SpringBoot project starts, the classloader loads the fully qualified class name of the factory implementation of the given type from meta-INF/Spring.Factories. That is, the classloader takes the meta-INF/Spring. factories file resources from all the JAR packages in the project, gets a collection of auto-configuration-related classes, instantiates them, and puts them into the Spring container.

The final project structure is as follows:

Build package using Maven’s install command in the development tool IDEA. Or in the project directory, open a command line window and use the MVN install command to build the package. Once packaged, a JAR package will be generated in the target directory of the project and the corresponding JAR package will be generated in the Maven local repository.

Use a custom Starter

After the above steps, our custom Starter has been developed. Here’s how to introduce it to other projects. Introduce this dependency in the POM.xml file of the project that needs to reference the Starter.

<dependency>
   <groupId>com.nobody</groupId>
   <artifactId>myjson-spring-boot-starter</artifactId>
   <version>0.0.1 - the SNAPSHOT</version>
</dependency>
Copy the code

Refresh the dependency, and you’ll see it in your project’s dependency library.

You can also view the properties that the Starter can configure as follows:

Then inject it into the class you want it to use.

package com.nobody.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.nobody.domain.Person;
import com.nobody.service.MyJsonService;

@RestController
@RequestMapping("demo")
public class DemoController {
    
    // Inject the service class in our Starter
    @Autowired
    private MyJsonService myJsonService;
    
    @GetMapping()
    public String test(a) {
        Person p = new Person("Mr.nobody".18.Las Vegas);
        // Invoke the service method
        returnmyJsonService.objectToMyJson(p); }}Copy the code

Start the project, access this interface in a browser, and get the following results:

If we add the following configuration information to the application.yml file and then access the interface, we get the following result, which also verifies that we can customize the default configuration items in Starter.

nobody: 
  json:
    prefixName: HH
    suffixName: KK
Copy the code

When we introduce the Starter, SpringBoot is automatically assembled to put the instantiated bean into the Spring container. But can we control whether or not a bean is instantiated and put into a container? The answer is yes.

All we need to do is in the auto-assemble class or the in-class method, with the @conditionalonxxx annotation. For example, as shown below, the MyJsonService instance will not be automatically generated if the Starter user sets the value of nod.json. enable to false in the configuration file of his project. If the default is left blank or the value of nobody. Json. enable is true, the bean is automatically generated and put into the container. This gives the user control over the bean’s instantiation.

// Create MyJsonService object and inject it into the Spring container
@Bean
@ConditionalOnProperty(name = "nobody.json.enable", matchIfMissing = true)
@ConditionalOnMissingBean(MyJsonService.class) // Only register when the container does not have this bean
public MyJsonService myJsonService(a) {
    MyJsonService myJsonService = new MyJsonService();
    myJsonService.setPrefixName(myJsonProperties.getPrefixName());
    myJsonService.setSuffixName(myJsonProperties.getSuffixName());
    return myJsonService;
}
Copy the code

This demo project has been uploaded to Github, if you need to download, welcome Star. Github.com/LucioChn/my…