Required Dependencies
The spring-boot-autoconfigure dependency provides Spring Boot's core auto-configuration capabilities, automatically setting up common components like database connections, caches, and message brokers based on your project's classpath and configuration. This eliminates manual setup for standard use cases.
The spring-boot-configuration-processor is a compile-time tool that enables IDEs to offer auto-completion and validation for properties injected via @Value or @ConfigurationProperties. Marked as optional, it’s only used during development and won’t be included in the final packaged JAR.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/>
</parent>
<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>
Implement Custom Service
Create a custom service class that leverages configuration properties to deliver tailored functionality. Using constructor injection improves immutability and testability:
import org.springframework.beans.factory.annotation.Autowired;
public class FeatureService {
private final FeatureSettings featureSettings;
@Autowired
public FeatureService(FeatureSettings featureSettings) {
this.featureSettings = featureSettings;
}
public void executeFeature() {
System.out.println("Executing custom feature service...");
System.out.println("Feature Configuration: " + featureSettings.toString());
}
}
Configure Property Binding
Define a configuration class to map external YAML properties to Java fields. Use @ConfigurationProperties with a custom prefix for binding:
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "app.feature")
public class FeatureSettings {
private String serviceName;
private String serviceVersion;
private String serviceDescription;
private String packageGroup;
private String packageArtifact;
private String packageVersion;
private String packageUrl;
private String packageLicense;
// Getters and Setters
public String getServiceName() { return serviceName; }
public void setServiceName(String serviceName) { this.serviceName = serviceName; }
public String getServiceVersion() { return serviceVersion; }
public void setServiceVersion(String serviceVersion) { this.serviceVersion = serviceVersion; }
public String getServiceDescription() { return serviceDescription; }
public void setServiceDescription(String serviceDescription) { this.serviceDescription = serviceDescription; }
public String getPackageGroup() { return packageGroup; }
public void setPackageGroup(String packageGroup) { this.packageGroup = packageGroup; }
public String getPackageArtifact() { return packageArtifact; }
public void setPackageArtifact(String packageArtifact) { this.packageArtifact = packageArtifact; }
public String getPackageVersion() { return packageVersion; }
public void setPackageVersion(String packageVersion) { this.packageVersion = packageVersion; }
public String getPackageUrl() { return packageUrl; }
public void setPackageUrl(String packageUrl) { this.packageUrl = packageUrl; }
public String getPackageLicense() { return packageLicense; }
public void setPackageLicense(String packageLicense) { this.packageLicense = packageLicense; }
@Override
public String toString() {
return "FeatureSettings{" +
"serviceName='" + serviceName + '\'' +
", serviceVersion='" + serviceVersion + '\'' +
", serviceDescription='" + serviceDescription + '\'' +
", packageGroup='" + packageGroup + '\'' +
", packageArtifact='" + packageArtifact + '\'' +
", packageVersion='" + packageVersion + '\'' +
", packageUrl='" + packageUrl + '\'' +
", packageLicense='" + packageLicense + '\'' +
'}';
}
}
Auto-Configuration Class
Create an auto-configuration class to register your service as a Spring bean. The @Import annotation ensures the property class is loaded into the application context:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import(FeatureSettings.class)
public class FeatureAutoConfiguration {
@Bean
public FeatureService featureService(FeatureSettings featureSettings) {
return new FeatureService(featureSettings);
}
}
Enable Auto-Discovery
To let Spring Boot automatically detect your configuration, create a META-INF/spring.factories file in the src/main/resources directory. Add an entry pointing to your auto-configuration class:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.yourorg.feature.config.FeatureAutoConfiguration
Test with Demo Project
Create a new Spring Boot project, add your custom starter as a dependency, and configure feature properties in application.yml:
project:
version: 1.0.0
spring:
application:
name: demo-app
app:
feature:
service-name: ${spring.application.name}
service-version: ${project.version}
service-description: "Custom Spring Boot Starter Demo"
package-group: com.yourorg
package-artifact: feature-starter
package-version: 1.0.0
package-url: "https://github.com/yourorg/feature-starter"
package-license: "MIT License"
In the demo project's main class, retrieve the FeatureService and invoke its method:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import com.yourorg.feature.service.FeatureService;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
FeatureService featureService = context.getBean(FeatureService.class);
featureService.executeFeature();
}
}
Running the demo application will print the configured feature details, confirming your custom starter works as intended. The configuration processor will also provide auto-completion for app.feature properties in your IDE during development.