Using springboot to customize starter development

summary

Springboot changes the complicated configuration files of spring MVC into parametric configuration, which makes users feel great convenience. Therefore, if you only use the off the shelf spring boot function, there is not much technical requirement. Then, based on the principle of improving yourself and writing code as gracefully as possible, how to realize parametric development for springboot? How to configure our own functions to parametric development? These two problems are deeply understood, and combined with the actual project, the encapsulated custom tools are implemented to facilitate the reference and use of other projects.
The related concepts will not be repeated. They are generally starter and autoconfiguration. Many great gods on the network give detailed explanations. The author wrote in detail, and the corresponding git address. You can see the source code. Thank him for his selfless sharing!
Reference materials: Customize one of the spring boot starter Trilogy: preparation

target

Create a custom starter that can be introduced into another project and call related functions.

Implementation: starter encapsulation

1. Create maven project




In particular, GroupId is usually the website suffix plus the organization name. Because I am a Chinese developer and this project is used for personal development and daily use, I use cn (top-level domain name of China Network). Wangchb (pinyin abbreviation of my personal name)
If the Name is required by the springboot official, the unofficial starter requires the user-defined Name to be written in front of the spring boot starter (XXX spring boot starter)

I have made a modular implementation here. Now I create a parent project, and the specific function implementation is in the charge of the specific module.

Create a completed project

Because it is the parent project, does not implement specific code and only manages modules, delete the src folder and leave only POM XML.

2. Modify POM XML 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>cn.wangchb</groupId>
    <artifactId>showsun-spring-boot-starter</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.RELEASE</version>
        <relativePath/>
    </parent>
    <modules>
        <module>api</module>
        <module>showsun-dynamicds-spring-boot-starter</module>
        <module>showsun-console-spring-boot-starter</module>
    </modules>
</project>

Modules contains all modules to be managed under your parent project
The parent must be introduced because we want the starter parent as our parent dependency
Since it is the parent project, add < packaging > POM < / packaging >

3. Create a sub module


There is no big difference between creating a module and creating a project, that is, you don't need to delete the src folder after creating it. Just pay attention to the naming specification of the module.

Here I have created three sub modules: API, showsun console spring boot starter and showsun dynamics spring boot starter.

4. Interface definition

We first define the service interface in the api module. For example, I want to encapsulate the service for the dynamic datasource (dynamic data source) to facilitate other project calls. Then I create the dynamic datasourceservice interface class in the api.

package cn.wangchb.api.service;


/**
 * Dynamic data source switching service class
 *
 * @Author: wangchb
 * @Date: 2021/8/4 14:13
 */
public interface DynamicDatasourceService {
    /**
     * Create database
     *
     * @param databaseName Database name
     * @return
     * @Author: wangchb
     * @Date: 2021/8/4 15:01
     **/
    boolean createDatabase(String databaseName);

    /**
     * Create table
     *
     * @param sql Create table sql statement
     * @return
     * @Author: wangchb
     * @Date: 2021/8/4 15:01
     **/
    boolean createTableBySql(String sql);
}

Here, I will simply define two interfaces, which means that my service will have two functions: creating a database and creating a table.

5. Interface implementation

Then it is implemented in my showsun dynamics spring boot starter module.
In order for the specific function module to get the api interface class, it needs to be in its POM Add to XML

<?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">
    <parent>
        <artifactId>showsun-spring-boot-starter</artifactId>
        <groupId>cn.wangchb</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>showsun-dynamicds-spring-boot-starter</artifactId>
    <dependencies>
        <dependency>
            <groupId>cn.wangchb</groupId>
            <artifactId>api</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>

</project>

Note: This is the POM of the showsun dynamics spring boot starter module XML file
Then implement the corresponding interface

package cn.wangchb.dynamicDatasourceService.service.impl;

import cn.wangchb.api.service.DynamicDatasourceService;

/**
 * Dynamic data source switching service interface implementation class
 *
 * @Author: wangchb
 * @Date: 2021/8/4 15:15
 */
public class DynamicDatasourceServiceImpl implements DynamicDatasourceService {
    @Override
    public boolean createDatabase(String databaseName) {
        System.out.println("Create database:" + databaseName);
        return false;
    }

    @Override
    public boolean createTableBySql(String sql) {
        System.out.println("Create table:" + sql);
        return false;
    }
}

For convenience, we don't need to write a specific implementation here. We can quickly implement our first step through console printing to verify whether we can package our own modules for quick call to other projects.
Now that we have finished the function development, we need to let springboot automatically inject our bean s, so we need to create a Configuration class
Then we need to introduce dependency in POM Add spring boot autoconfigure to XML

<dependencies>
        <dependency>
            <groupId>cn.wangchb</groupId>
            <artifactId>api</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
    </dependencies>

Write the interface configuration class DynamicDatasourceAutoConfiguration

package cn.wangchb.dynamicDatasourceService;

import cn.wangchb.api.service.DynamicDatasourceService;
import cn.wangchb.dynamicDatasourceService.service.impl.DynamicDatasourceServiceImpl;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Dynamic data source switching service configuration class
 *
 * @Author: wangchb
 * @Date: 2021/8/4 15:28
 */
@Configuration
public class DynamicDatasourceAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean(DynamicDatasourceService.class)
    public DynamicDatasourceService getDynamicDatasourceService() {
        return new DynamicDatasourceServiceImpl();
    }
}

@The Configuration annotation declares that this class is a Configuration class, which helps us scan and register the bean s under this class when the project is started
@ConditionalOnMissingBean. In this code, it means that if the class DynamicDatasourceService is not registered, you need to use the getDynamicDatasourceService method to register the bean.

Create a new META-INF folder under the resources directory, and create a new file spring. Inf in the folder factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.wangchb.dynamicDatasourceService.DynamicDatasourceAutoConfiguration

The corresponding configuration class created by ourselves can be introduced here.
The project structure is as follows:

6. Build packaging

Open the console, enter the root node directory of our parent project, and enter the command

mvn clean install -Dmaven.test.skip=true -U


Generally, there will be no problem. It shows that all modules are built successfully.
Here, our customized starter is encapsulated and has been installed into our local maven library. If other items on the same machine need to be used, just POM XML can be imported and used.

Implementation: reference custom starter

At this time, I create a new test project (spring Initializr)

Introduce the starter we created ourselves

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cn.wangchb</groupId>
    <artifactId>test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>test</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>cn.wangchb</groupId>
            <artifactId>showsun-dynamicds-spring-boot-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>


For convenience, a controller class is built, which directly defines the two simplest interfaces

package cn.wangchb.test;

import cn.wangchb.api.service.DynamicDatasourceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * Tool test
 *
 * @Author: wangchb
 * @Date: 2021/8/4 15:57
 */
@RestController
public class datasourceController {
    @Autowired
    DynamicDatasourceService dynamicDatasourceService;

    @RequestMapping(value = "/database", method = RequestMethod.GET)
    public boolean createDatabase() {
        return dynamicDatasourceService.createDatabase("I'm the watch name");
    }

    @RequestMapping(value = "/table", method = RequestMethod.GET)
    public boolean createTable() {

        return dynamicDatasourceService.createTableBySql("I am sql sentence");
    }
}

The test engineering structure is as follows:

Start the service, and the browser will access it respectively
http://localhost:8080/table
http://localhost:8080/database
You can see that we can call the service we encapsulated before

This is the initial completion. The configuration file has not been used in the example. Later, we can add configuration items to make the functions more flexible.

Keywords: Java Spring Spring Boot

Added by suncore on Mon, 03 Jan 2022 07:27:23 +0200