Configuration Management, Filters, and Interceptors in Spring Boot
Reading Application Configurations
In a Spring Boot project, the src/main/resources directory serves as the primary location for configuration files. The framework natively supports application.properties and application.yml. Using YAML allows for a more readable, hierarchical structure for custom properties.
Using @ConfigurationProperties
To map structured configuration data directly into Java objects, combine @Component with @ConfigurationProperties. For instance, define the following in application.yml:
service:
metadata:
instance-name: "PaymentService"
timeout-seconds: 30
The corresponding Java class uses a prefix to filter relevant keys:
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "service.metadata")
public class ServiceConfig {
private String instanceName;
private int timeoutSeconds;
// Standard Getters and Setters
public String getInstanceName() { return instanceName; }
public void setInstanceName(String instanceName) { this.instanceName = instanceName; }
public int getTimeoutSeconds() { return timeoutSeconds; }
public void setTimeoutSeconds(int timeoutSeconds) { this.timeoutSeconds = timeoutSeconds; }
}
External Configuration Files
If project requirements necessitate separating configurations into multiple files, the @PropertySource annotation allows you to load specific .properties files from the classpath.
@Component
@PropertySource("classpath:custom-settings.properties")
@ConfigurationProperties(prefix = "custom")
public class ExternalSettings {
private String apiToken;
public String getApiToken() { return apiToken; }
public void setApiToken(String apiToken) { this.apiToken = apiToken; }
}
Implementing Servlet Filters
Filters operate at the lowest level of the request processing pipeline, allowing for the inspection or modification of requests before they reach the DispatcherServlet. Typical use cases include logging, authentication, and CORS handling.
Custom Filter Implementation
Implementing the javax.servlet.Filter interface envolves overriding the doFilter method. In the example below, the filter checks for a specific security header.
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class SecurityHeaderFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
String authHeader = req.getHeader("X-Custom-Auth");
if ("secure-token-123".equals(authHeader)) {
chain.doFilter(request, response);
} else {
HttpServletResponse res = (HttpServletResponse) response;
res.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
res.getWriter().write("Unauthorized: Missing or invalid security header.");
}
}
}
Registering the Filter
To apply the filter to specific URL patterns, use the FilterRegistrationBean inside a configuration class.
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<SecurityHeaderFilter> registerSecurityFilter() {
FilterRegistrationBean<SecurityHeaderFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new SecurityHeaderFilter());
registrationBean.addUrlPatterns("/api/secure/*");
registrationBean.setOrder(1); // Lower values indicate higher priority
return registrationBean;
}
}
Working with Interceptors
Interceptors are part of the Spring MVC framework. They provide fine-grained control by intercepting requests handled by Spring controllers. They are ideal for cross-cutting concerns like execution timing or locale resolution.
Creating an Interceptor
The HandlerInterceptor provides three hooks: preHandle (before controller execution), postHandle (after execution but before view rendering), and afterCompletion (after the request is fully completed).
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ExecutionTimerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
long startTime = (Long) request.getAttribute("startTime");
long endTime = System.currentTimeMillis();
System.out.println("Request [" + request.getRequestURI() + "] processed in: " + (endTime - startTime) + "ms");
}
}
Enterceptor Registration
To activate the interceptor, implement the WebMvcConfigurer interface and override the addInterceptors method.
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ExecutionTimerInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/static/**", "/error");
}
}