How to Build Your Own Spring Boot Starter: Step‑by‑Step Guide
This article walks you through creating a custom Spring Boot Starter, covering project setup, Maven dependencies, auto‑configuration classes, registration via spring.factories (or the new imports file), and comprehensive unit testing strategies to ensure reliable conditional behavior.
Quick Start
Create a new Maven project. Name the starter using the pattern 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, 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. Use /META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports instead, listing the fully‑qualified class names of auto‑configuration classes.
Validation Tests
When building a Spring Boot Starter, always write unit tests to verify that the auto‑configuration behaves as expected under various conditions.
Create Unit Tests
Use @SpringBootTest to load the full application context and assert 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 on @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 contains conditional annotations like @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 testing.
Summary
The article covered two advanced Spring Boot topics: how to create a Spring Boot Starter and how to provide comprehensive unit tests for it. Mastering these skills enables you to package reusable modules and ensure they work reliably in any Spring Boot application.
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.
