How to make your custom Spring boot starter component?

HBLOG
4 min readMar 11, 2024

--

一、Why customize spring boot starter

In our daily development work, we often have some configuration modules that are independent of the business. We often put them under a specific package, and then if another project needs to reuse this function, the code needs to be Hard copying it to another project and re-integrating it is extremely troublesome. If we encapsulate these functional configuration modules that are independent of the business code into starters, we only need to reference them in the pom as dependencies when reusing them. SpringBoot completes the automatic assembly for us, which is really cool.

二、how to make it?

Although different starters have different implementations, they basically use the same two contents: ConfigurationProperties and AutoConfiguration. Because Spring Boot firmly believes in the concept of “convention over configuration”, we use ConfigurationProperties to save our configurations, and these configurations can have a default value, that is, if we do not actively overwrite the original configuration, the default value will takes effect, which is very useful in many situations. In addition, the starter’s ConfigurationProperties also allows all configuration properties to be gathered into one file (usually application.properties in the resources directory), so we say goodbye to the XML hell in the Spring project.

三、Naming conventions

If you are about to have a baby, you must be most anxious about choosing a name before the birth. The child’s name marks the bloodline of you and your lover. It will definitely not have the surname of the old man next door, and it will definitely attract strange eyes. In maven, groupId represents the last name and artifactId represents the first name. Spring Boot also has a naming suggestion. Therefore, the name cannot be obtained casually. You can choose it according to the official recommendations.。

What’s in a name All official starters follow a similar naming pattern; spring-boot-starter- , where is a particular type of application. This naming structure is intended to help when you need to find a starter. The Maven integration in many IDEs lets you search dependencies by name. For example, with the appropriate Eclipse or STS plugin installed, you can press ctrl-space in the POM editor and type “spring-boot-starter” for a complete list. As explained in the “Creating Your Own Starter” section, third party starters should not start with spring-boot, as it is reserved for official Spring Boot artifacts. Rather, a third-party starter typically starts with the name of the project. For example, a third-party starter project called thirdpartyproject would typically be named thirdpartyproject-spring-boot-starter.

四、Code project

pom.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>springboot-demo</artifactId>
<groupId>com.et</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>xxx-spring-boot-starter</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

application.properties

com.person.age=23
com.person.name=Lynch
com.person.sex=F

auto configuration

package com.et.config;
import com.et.service.PersonService;
import com.et.starter.PersonProperties;
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;
@Configuration
@EnableConfigurationProperties(PersonProperties.class)
@ConditionalOnClass(PersonService.class)
@ConditionalOnProperty(prefix = "com.person", value = "enabled", matchIfMissing = true)
public class PersonServiceAutoConfiguration {
@Autowired
private PersonProperties properties;
// if spring container do not config bean,auto config PersonService
@Bean
@ConditionalOnMissingBean(PersonService.class)
public PersonService personService(){
PersonService personService = new PersonService(properties);
return personService;
}
}

service

package com.et.service;
import com.et.starter.PersonProperties;
public class PersonService {
private PersonProperties properties;
public PersonService() {
}
public PersonService(PersonProperties properties) {
this.properties = properties;
}
public void sayHello() {
String message = String.format("hi,my name: %s, today,I'am %s , gender: %s",
properties.getName(), properties.getAge(), properties.getSex());
System.out.println(message);
}
}

PersonProperties.java

package com.et.starter;
import java.io.Serializable;
import org.springframework.boot.context.properties.ConfigurationProperties;
@SuppressWarnings("serial")
@ConfigurationProperties(prefix = "com.person")
public class PersonProperties implements Serializable {
private String name;
private int age;
private String sex = "M";
public PersonProperties() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}

spring.factories

The /META-INF/spring.factories file is placed in the /src/main/resources directory. Note: META-INF is a directory manually created by yourself, and spring.factories is also a file you manually created. Configure your own automatic configuration in this file. kind.

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.et.config.PersonServiceAutoConfiguration

project package

mvn clean install

Code repository

五、Test

Add starter dependencies to another project

<dependency>
<groupId>com.et</groupId>
<artifactId>xxx-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

unit test

package com.et.starter;
import com.et.service.PersonService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private PersonService personService;
@Test
public void testHelloWorld() {
personService.sayHello();
}
}

run test

2024-03-11 10:35:18.374 INFO 10960 --- [ main] com.et.starter.PersonServiceTest : Starting PersonServiceTest on BJDPLHHUAPC with PID 10960 (started by Dell in D:\IdeaProjects\ETFramework\xxx-spring-boot-starter-test)
2024-03-11 10:35:18.376 INFO 10960 --- [ main] com.et.starter.PersonServiceTest : No active profile set, falling back to default profiles: default
2024-03-11 10:35:19.387 INFO 10960 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2024-03-11 10:35:19.657 INFO 10960 --- [ main] com.et.starter.PersonServiceTest : Started PersonServiceTest in 1.507 seconds (JVM running for 2.188)
hi,my name: Lynch, today,I'am 23 , gender: F
2024-03-11 10:35:19.827 INFO 10960 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'

六、reference

--

--

HBLOG
HBLOG

Written by HBLOG

talk is cheap ,show me your code

No responses yet