Build Your Own Spring Boot Starter: A Step‑by‑Step Guide
This tutorial explains how to create a custom Spring Boot Starter, covering project setup, Maven dependencies, auto‑configuration class creation, registration via spring.factories, and comprehensive unit testing to ensure correct conditional behavior.
When you want to package custom functionality for others, creating a Spring Boot Starter is the optimal approach. This guide walks you through building your own starter from scratch.
Quick Start
Create a new Maven project. Use the naming convention xxx-spring-boot-starter, e.g., didispace-spring-boot-starter.
Edit pom.xml and add the spring-boot-autoconfigure and spring-boot-starter dependencies.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
</dependencies>Create a configuration class annotated with @Configuration. Inside you can define beans using @Bean and control their loading with conditional annotations such as @ConditionalOnClass and @ConditionalOnMissingBean.
@Configuration
@ConditionalOnClass(MyFeature.class)
@ConditionalOnProperty(prefix="myfeature", name="enabled", matchIfMissing=true)
public class MyFeatureAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyFeature myFeature() {
return new MyFeature();
}
}Under src/main/resources/META-INF create a spring.factories file and list your auto‑configuration class under the
org.springframework.boot.autoconfigure.EnableAutoConfigurationkey.
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.didispace.myfeature.MyFeatureAutoConfigurationNote: Starting with Spring Boot 2.7, spring.factories is deprecated in favor of /META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports , where you simply list the fully‑qualified configuration class names.
Verification Tests
Use unit tests to ensure that the auto‑configuration behaves as expected under various conditions.
Create Unit Tests
Annotate a test class with @SpringBootTest to load the full application context and verify that beans and properties are correctly configured.
@SpringBootTest(classes = TestApplication.class)
public class MyStarterAutoConfigurationTest {
@Autowired(required = false)
private MyService myService;
@Test
public void testMyServiceAutoConfigured() {
assertNotNull(myService, "MyService should be auto-configured");
}
}Override Different Configurations
Use @TestPropertySource or @DynamicPropertySource to supply alternative property values, or set properties directly in @SpringBootTest.
@SpringBootTest(properties = "my.starter.custom-property=customValue")
public class MyStarterPropertiesTest {
@Value("${my.starter.custom-property}")
private String customProperty;
@Test
public void testPropertyOverride() {
assertEquals("customValue", customProperty, "Custom property should be overridden by @SpringBootTest");
}
}Test Conditional Branches
If your starter uses conditional annotations such as @ConditionalOnProperty or @ConditionalOnClass, write tests that cover each branch.
@SpringBootTest(classes = {TestApplication.class, MyConditionalConfiguration.class})
@ConditionalOnProperty(name = "my.starter.enable", havingValue = "true")
public class MyStarterConditionalTest {
@Autowired
private ApplicationContext context;
@Test
public void conditionalBeanNotLoadedWhenPropertyIsFalse() {
assertFalse(context.containsBean("conditionalBean"),
"Conditional bean should not be loaded when 'my.starter.enable' is false");
}
}Use @TestConfiguration to selectively enable or disable auto‑configuration classes during tests.
Conclusion
This article covered two advanced Spring Boot topics: how to create a Spring Boot Starter and how to provide unit tests for it. Mastering these skills enables you to modularize and share functionality across Spring Boot applications.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
