Recently, I am organizing the content of the company’s public starter. I also want to write an article about starter, so that more partners who do not know about it can master this core skill

This article from zero to one packaging design starter, and provides plugable starter and metadata configuration and other instructions, and in the plugable and open source Zuul comparison, I hope you have some gain after reading

The outline of the article is as follows:

  • starter
    • The starter is defined
    • The starter benefits
  • Custom starter
    • The starter named
    • Create a SpringBoot project
    • Pom dependency configuration
    • Auto-configuration class
    • spring.factories
    • Packaging warehouse
    • Testing the starter
  • Pluggable starter
    • A self-definable swappable starter
    • Zuul implements pluggable principle
  • Configuring metadata
  • “Said

Article first from the public number [source interest circle], concerned about the public number for the first time to obtain back-end core knowledge, has issued [45] original technology blog

starter

The starter is defined

Springboot Starter is similar to a plug-in mechanism, which abandons the previous tedious configuration and integrates complex dependencies into the starter

All dependency modules follow the convention default configuration and allow us to adjust these configurations, following the “convention over configuration” philosophy

The starter benefits

The emergence of starter has greatly helped developers to focus on business code by freeing them from tedious framework configuration

In addition, Springboot officially provides starter dependency modules for different scenarios of enterprise-level projects, which can be easily integrated into projects

For example, the Springboot project needs to rely on Redis. We only need to add the spring-boot-starter-data-redis dependency and configure some necessary connection information

The user only needs to reference the starter dependency, and SpringBoot can automatically load the configuration dependencies required by the project, eliminating the problem of different dependency library references and versioning

Custom starter

The starter named

Starter pack artifactids are mandatory, but they are optional (after all, you are in charge of your project)

Spring officially provides the starter, usually named spring-boot-starter-{name} for example:

Spring-boot-starter -web, spring-boot-starter- ActivemQ, etc. Here are some official lists. For details, see the SpringBoot starter list

Spring recommends that the unofficially provided starter be named in the {name}-spring-boot-starter format

For example, mybatis produces: Mybatis – Spring-boot-starter

Create a SpringBoot project

Starter is also created based on the SpringBoot project, so the first step should be to create a SpringBoot project

After the project is created, delete unnecessary files in the following directory:

├ ─ ─ pom. XML └ ─ ─ the SRC ├ ─ ─ the main │ ├ ─ ─ Java │ │ └ ─ ─ cn │ │ └ ─ ─ machen │ │ └ ─ ─ the starter │ │ └ ─ ─ demospringbootstarter │ └ ─ ─ resourcesCopy the code

Pom dependency configuration

The dependencies in PUM.xml are very succinct; in addition to the project’s basic information and parent class references, all you need to do is refer to spring-boot-starter


      
<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.2.11. RELEASE</version>
        <relativePath/> <! -- lookup parent from repository -->
    </parent>
    <groupId>cn.machen.starter</groupId>
    <artifactId>demo-spring-boot-starter</artifactId>
    <version>0.0.1 - the SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

</project>
Copy the code

Auto-configuration class

Create a Service class registered as a Spring Bean that provides a sayHello method for subsequent testing

public class ServiceBean {
    public String sayHello(String name) {
        return String.format("Hello World, %s", name); }}Copy the code

Create the auto-configuration class, make the ServiceBean a declaration Bean, and wait for the scan to be delivered to the Spring IOC container

@Configuration
public class AutoConfigurationTest {
    
    @Bean
    public ServiceBean getServiceBean(a) {
        return newServiceBean(); }}Copy the code

spring.factories

Create a new meta-INF folder under the resources directory of the project and create the Spring. factories file

The autoconfigure file defines the configuration class as the configuration for auto-assembly

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  cn.machen.starter.demospringbootstarter.AutoConfigurationTest
Copy the code

Why do you specify spring.factories under resources/ meta-inf? I can’t write it that way

SpringFactoriesLoader#loadFactories is responsible for loading the autowler class and scanning this variable file

You don’t write according to the regulation can, can not sweep your automatic configuration class how to do, calm down

Packaging warehouse

The starter we provide must be referenced by third parties or our other projects, so package the project and publish it to the repository

Maven commands are package, install, and deploy commands

For the record, all three commands can be packaged, so what’s the difference?

Package:

This command completes three processes of project compilation, unit test and package function

Install:

A new step is added under the package command to deploy the newly packaged package to the local Maven repository

Deploy:

Add a step under the install command to deploy the new package to the remote repository (equivalent to deploying a copy of both the local and remote repositories)

However, we only reference the local repository and only need to execute the install command. The two methods are maven plug-in or terminal execution command MVN clean install

You can go to the corresponding repository coordinates to check whether the JAR is successfully deployed

Testing the starter

How do we test the success of our newly created starter? Create a new project that references the Starter project coordinates

<? 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.211..RELEASE</version> <relativePath/> <! -- lookup parent from repository --> </parent> <groupId>cn.machen.starter</groupId> <artifactId>demo-test-spring-boot-starter</artifactId> <version>0.01.-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <! Starter --> <dependency> <groupId>cn.machen.starter</groupId> <artifactId>demo-spring-boot-starter</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> </project>Copy the code

Since it is a test, what kind of standard is passed?

According to the code defined in our starter, the Demo-test project is successful as long as it references ServiceBean and prints the corresponding information

The src-main-test directory uses the project to create its own test class

@SpringBootTest
class DemoTestSpringBootStarterApplicationTests {

    @Autowired
    private ServiceBean serviceBean;

    @Test
    void contextLoads(a) {
        System.out.println(serviceBean.sayHello("machen")); }}Copy the code

Run the contextLoads test and output Hello World, machen

You think this is the end of it? No, no, no. Hardcore, dry knowledge is just beginning

Pluggable starter

A self-definable swappable starter

A starter is a starter. It’s called pluggable

Pluggable literally means that although I’ve introduced your starter JAR package, I can conditionally determine whether or not to load your functionality

If the conditions are met, load the jar configuration. If not, go to sleep.

There are many ways to implement pluggability, through configuration file key prefixes or custom annotations, but none of these circumvent springBoot conditional annotations

The article uses custom annotation + conditional annotation form to complete, the rest here is not one example, we can search online

demo-spring-boot-starter

1) First create custom annotations in your project

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EnableAutoConfigTest { }
Copy the code

2) Add conditional annotations to the AutoConfigurationTest class and repackage to the local repository

@Configuration
@ConditionalOnBean(annotation = EnableAutoConfigTest.class)
public class AutoConfigurationTest {

    @Bean
    public ServiceBean getServiceBean(a) {
        return newServiceBean(); }}Copy the code

demo-test-spring-boot-starter

1) Reference the @enableAutoConfigTest annotation in the main program

@EnableAutoConfigTest
@SpringBootApplication
public class DemoTestSpringBootStarterApplication {
    public static void main(String[] args) { SpringApplication.run(DemoTestSpringBootStarterApplication.class, args); }}Copy the code

Test removable starter

Running the program in the test class above will print our Hello World as normal

Delete @enableAutoConfigTest and try it out

Unsatisfied dependency expressed through field 'serviceBean'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'cn.machen.starter.demospringbootstarter.ServiceBean' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Copy the code

Of course, the formal environment can not be implemented so rough ha, however, the train of thought is consistent

Previously, I participated in the company’s search business package starter, which was completed by using the above user-defined annotations combined with conditional annotations

In fact, in addition to the pluggable implementation of the article, springCloud Zuul is also a similar idea, because it is not a good game

Zuul implements pluggable principle

We typically enable Zuul injection by configuring the Zuul annotation @enableZuulProxy on the configuration class

The @import annotation was covered in detail in the previous article # Deeper Understanding Spring @import’s different ways of registering beans

What does the red class do

From the comments on the class:

Responsible for adding tags bean to trigger the activation of {@ link ZuulProxyAutoConfiguration}

In fact, here is already very clear, but in line with the good quality of responsible in the end, continue to follow up

In line with the idea of customizable pluggable starter above, pluggable features are implemented through a tag

The difference is that zuul used a meaningless bean to mark it up, whereas we use annotations

Configuring metadata

Do you wonder how to realize the intelligent prompt when you input it in the project configuration file?

Take server. XXX as an example, open spring-configuration-metadata.json in the SpringBoot source package with doubts

Are you familiar with defaultValue and Description? This is the default value of the above prompt and the prompt message

How does this file come about? There are two ways

  1. The developer can manually configure metadata.json by creating meta-INF /spring-configuration-metadata.json file
  2. Another is generated automatically through the @ConfigurationProperties annotation

There are automatically generated must be preferred use ah, after all I am such a lazy person. You only need to perform three simple operations in the starter package to configure metadata

1) Add the spring-boot-configuration-processor package to reference POM. XML

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
Copy the code

2) Write the Properties configuration class, using the Swagger example

@Data
@Configuration
@ConfigurationProperties(prefix = "swagger")
public class SwaggerProperties {

    /** * Document scan package path */
    private String basePackage = "";

    /** * title Example: order creation interface */
    private String title = "Platform System Interface Details";

    /** * Terms of Service website */
    private String termsOfServiceUrl = "https://www.xxxx.com/";

    /** * Version number */
    private String version = "V_1. 0.0";

}
Copy the code

3) Finally run the package command to update the jar package of the local repository

mvn clean install
Copy the code

Next update the reference in the demo-test-spring-boot-starter project and test it in application.properties

Such a device must be popular with relatives and friends [dog head]

How to implement mybatis Starter

We refer to the related POM package dependencies. If you can’t find the related dependencies, you can search the public repository

Public repository address: mvnrepository.com/

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>
Copy the code

Check the contents of mybatis starter pack. Is it consistent with our customization

According to? Why is there no configuration meta information in this? Click on pom.xml, where you might find the answer

You can see that pop.xml contains mybatis-spring-boot-autoconfigure, mybatis, mybatis-spring dependencies

The secret to making mybatis globally initialized is in mybatis-spring-boot-autoconfigure

Mybatis -spring-boot-autoconfigure contains the initialization configuration class MybatisAutoConfiguration, in which the mybatis related initialization is done

What is the difference between mybatis starter design and the custom starter we mentioned above?

Mybatis Starter doesn’t do anything, it just does a combined dependency, and it initializes the autoconfigure package

Springboot does the same thing, except it finds autoconfigure implementations for all packages uniformly, as you can see by looking at spring-boot-Autoconfigure-xxx. jar

However, our custom starter does not rely on the autoconfigure package. The two are not right or wrong, but the embodiment of different design. There is no suggestion here, it depends on personal preference

What? You said to go with the mainstream and strictly implement springboot?

I thought you’d think so, which is why we brought in Netflix

Understand people naturally understand, see the mood starter, all day long to write BUG of the Internet ~

“Said

It has been a week since I posted my last article, during which I have done three things:

  1. Understand DevOps concepts and optimize some of the company’s DevOps components
  2. Completed the construction of personal technology blog website
  3. The message leaving function is enabled by migrating the public account

DevOps

DevOps is an issue that the author hasn’t had much exposure to before, so it took some time to conceptualize

  1. What is waterfall development? What are the advantages and disadvantages?
  2. What is Agile development? What are the advantages and disadvantages?
  3. What is DevOps? What is CI/CD?

After these days of understanding and building and using basic components, I have mastered a lot better than before and gained a lot

Why build a personal blog?

Having a personal technology blog is probably the idea of many programmers, and of course, I am no exception, having built a static blogging system through Hexo in April of nineteen nineteen

But back then blogs were full of bells and whistles, and now they prefer a simpler look, as shown here:

Welcome to blog.machen.me/

Leave messages on public account

The public number is 18 years of registration, has been no message function, but their own more like

Because after the message, you can better through the feedback of readers to recognize their own to improve or wrong content

After the transfer of message function from the public account, this is the first article, see here friends can leave a message to test it

Recommended reading:

  • ParallelStream Is a new feature in JDK 8
  • How does Redisson implement distributed locking principle
  • [Highly recommended] Talk about ReentrantLock and AQS
  • How to quickly consume tasks in the JDK thread pool without exceeding the maximum number of threads
  • How does the JDK thread pool ensure that core threads are not destroyed

Author Mahua, coordinate Java backend research and development, aspiring to become an architect of a Virgo programmer, focus on high concurrency, framework source code, distributed and other knowledge sharing