Creating a Custom Spring Boot Starter with Auto-Configuration

Begin by creating a new Maven project. The pom.xml should define the Spring Boot parent and include the web sttarter dependency.

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.0</version>
    <relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>custom-logging-starter</artifactId>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

Next, implement a servlet filter that logs incoming HTTP requests. This serves as the functional component of the starter.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

public class RequestLoggingFilter implements Filter {
    private static final Logger LOGGER = LoggerFactory.getLogger(RequestLoggingFilter.class);

    @Override
    public void init(FilterConfig filterConfig) {
        LOGGER.info("Initializing RequestLoggingFilter.");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        LOGGER.info("Processing request for URI: {}", httpRequest.getRequestURI());
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        LOGGER.info("Destroying RequestLoggingFilter.");
    }
}

Register this filter as a Spring bean using a FilterRegistrationBean. This bean configures the URL patterns and order.

import org.springframework.boot.web.servlet.FilterRegistrationBean;

public class RequestLoggingFilterRegistration extends FilterRegistrationBean<RequestLoggingFilter> {
    public RequestLoggingFilterRegistration() {
        super();
        this.setFilter(new RequestLoggingFilter());
        this.addUrlPatterns("/*");
        this.setName("requestLoggingFilter");
        this.setOrder(Ordered.HIGHEST_PRECEDENCE);
    }
}

Create a auto-configuration class that conditionally registers the filter bean. This class uses @ConditionalOnClass to ensure it only loads when the required classes are present.

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConditionalOnClass({RequestLoggingFilter.class, RequestLoggingFilterRegistration.class})
public class RequestLoggingAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public RequestLoggingFilterRegistration requestLoggingFilterRegistration() {
        return new RequestLoggingFilterRegistration();
    }
}

Define a custom annotation to enable this starter's functionality. This annotation will trigger the import of the auto-configuration.

import org.springframework.context.annotation.Import;
import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(RequestLoggingSelector.class)
public @interface EnableRequestLogging {
}

Implement a DeferredImportSelector to load the auto-configuration class from the spring.factories file.

import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.context.annotation.DeferredImportSelector;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.type.AnnotationMetadata;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;

public class RequestLoggingSelector implements DeferredImportSelector, BeanClassLoaderAware {
    private ClassLoader classLoader;
    private final Class<?> annotationType = EnableRequestLogging.class;

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        List<String> configurations = new ArrayList<>(
            new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(this.annotationType, this.classLoader))
        );
        return configurations.toArray(new String[0]);
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }
}

Create a spring.factories file in the src/main/resources/META-INF/ directory. This file maps the enabling annotation to the auto-configuration class.

com.example.annotation.EnableRequestLogging=com.example.config.RequestLoggingAutoConfiguration

To use the starter in another project, add it as a dependency.

<dependency>
    <groupId>com.example</groupId>
    <artifactId>custom-logging-starter</artifactId>
    <version>1.0.0</version>
</dependency>

Final, annotate the main application class with @EnableRequestLogging to activate the auto-configured filter.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableRequestLogging
public class SampleApplication {
    public static void main(String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }
}

Tags: Spring Boot auto-configuration starter Servlet Filter java

Posted on Thu, 02 Jul 2026 16:33:54 +0000 by traxy