Spring Boot 拦截器(Interceptor)详解
引言
Spring Boot拦截器是Spring MVC框架的重要组成部分,用于在请求处理的各个阶段执行预处理和后处理逻辑。拦截器在Web应用的安全控制、日志记录、性能监控、权限验证等方面发挥着重要作用,是构建高质量Web应用的基础组件之一。
拦截器基础概念
拦截器的作用和原理
拦截器是Spring MVC框架提供的机制,用于在Controller方法执行前后、视图渲染前后执行特定逻辑。拦截器遵循责任链模式,多个拦截器可以组成拦截器链,按照配置顺序依次执行。
拦截器生命周期
拦截器具有完整的生命周期管理,包含三个主要方法:
- preHandle():Controller方法执行前调用
- postHandle():Controller方法执行后,视图渲染前调用
- afterCompletion():整个请求处理完成后调用
拦截器实现方式
实现HandlerInterceptor接口
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CustomInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandle: 请求处理前执行");
// 获取请求信息
String requestURI = request.getRequestURI();
String method = request.getMethod();
String userAgent = request.getHeader("User-Agent");
System.out.println("请求URI: " + requestURI);
System.out.println("请求方法: " + method);
System.out.println("User-Agent: " + userAgent);
// 验证逻辑
if (requestURI.contains("/admin") && !isAdminUser(request)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("Access denied");
return false; // 阻止请求继续执行
}
return true; // 继续执行
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle: Controller执行后,视图渲染前执行");
// 可以修改ModelAndView
if (modelAndView != null) {
modelAndView.addObject("currentTime", System.currentTimeMillis());
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion: 请求处理完成后执行");
if (ex != null) {
System.out.println("请求处理发生异常: " + ex.getMessage());
}
// 记录请求处理时间
Long startTime = (Long) request.getAttribute("startTime");
if (startTime != null) {
long duration = System.currentTimeMillis() - startTime;
System.out.println("请求处理耗时: " + duration + "ms");
}
}
private boolean isAdminUser(HttpServletRequest request) {
// 简单的管理员验证逻辑
String adminToken = request.getHeader("X-Admin-Token");
return "admin-secret-token".equals(adminToken);
}
}
使用@Component注解
import org.springframework.stereotype.Component;
@Component
public class ComponentInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("ComponentInterceptor preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("ComponentInterceptor postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
System.out.println("ComponentInterceptor afterCompletion");
}
}
Spring Boot拦截器配置
使用WebMvcConfigurer
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册自定义拦截器
registry.addInterceptor(new CustomInterceptor())
.addPathPatterns("/**") // 拦截所有请求
.excludePathPatterns("/login", "/register", "/public/**"); // 排除特定路径
// 注册组件拦截器
registry.addInterceptor(new ComponentInterceptor())
.addPathPatterns("/api/**"); // 只拦截API请求
}
}
使用Bean配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class InterceptorBeanConfig {
@Bean
public CustomInterceptor customInterceptor() {
return new CustomInterceptor();
}
}
常见拦截器实现
日志拦截器
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LoggingInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String requestURI = request.getRequestURI();
String method = request.getMethod();
String remoteAddr = request.getRemoteAddr();
String userAgent = request.getHeader("User-Agent");
logger.info("请求开始 - URI: {}, Method: {}, IP: {}, User-Agent: {}",
requestURI, method, remoteAddr, userAgent);
// 记录开始时间
request.setAttribute("startTime", System.currentTimeMillis());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
String requestURI = request.getRequestURI();
int status = response.getStatus();
Long startTime = (Long) request.getAttribute("startTime");
long duration = startTime != null ? System.currentTimeMillis() - startTime : 0;
logger.info("请求结束 - URI: {}, Status: {}, Duration: {}ms",
requestURI, status, duration);
if (ex != null) {
logger.error("请求异常 - URI: {}, Error: {}", requestURI, ex.getMessage(), ex);
}
}
}
权限拦截器
public class AuthorizationInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String token = request.getHeader("Authorization");
if (token == null || !isValidToken(token)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("{\"error\":\"Unauthorized\"}");
return false;
}
// 验证权限
String requiredPermission = getRequiredPermission(request.getRequestURI());
if (!hasPermission(token, requiredPermission)) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.getWriter().write("{\"error\":\"Forbidden\"}");
return false;
}
return true;
}
private boolean isValidToken(String token) {
// 简单的token验证逻辑
return token.startsWith("Bearer ") && token.length() > 10;
}
private String getRequiredPermission(String uri) {
// 根据URI确定所需权限
if (uri.contains("/admin")) {
return "ADMIN";
} else if (uri.contains("/user")) {
return "USER";
}
return "GUEST";
}
private boolean hasPermission(String token, String requiredPermission) {
// 权限验证逻辑
return true; // 简化示例
}
}
性能监控拦截器
import java.util.concurrent.ConcurrentHashMap;
public class PerformanceInterceptor implements HandlerInterceptor {
private final ConcurrentHashMap<String, RequestStats> stats = new ConcurrentHashMap<>();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
request.setAttribute("startTime", System.currentTimeMillis());
request.setAttribute("startNanoTime", System.nanoTime());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
Long startTime = (Long) request.getAttribute("startTime");
Long startNanoTime = (Long) request.getAttribute("startNanoTime");
if (startTime != null && startNanoTime != null) {
long duration = System.currentTimeMillis() - startTime;
long nanoDuration = System.nanoTime() - startNanoTime;
String uri = request.getRequestURI();
String method = request.getMethod();
String fullUri = method + " " + uri;
stats.computeIfAbsent(fullUri, k -> new RequestStats())
.update(duration, nanoDuration);
// 记录慢请求
if (duration > 1000) {
// 超过1秒的请求
System.out.println("慢请求: " + fullUri + ", 耗时: " + duration + "ms");
}
}
}
public void printStats() {
stats.forEach((uri, stat) -> {
System.out.printf("URI: %s, Avg: %.2fms, Min: %dms, Max: %dms, Count: %d%n",
uri, stat.getAverage(), stat.getMin(), stat.getMax(), stat.getCount());
});
}
private static class RequestStats {
private long totalDuration = 0;
private long totalNanoDuration = 0;
private long requestCount = 0;
private long minDuration = Long.MAX_VALUE;
private long maxDuration = 0;
public synchronized void update(long duration, long nanoDuration) {
totalDuration += duration;
totalNanoDuration += nanoDuration;
requestCount++;
minDuration = Math.min(minDuration, duration);
maxDuration = Math.max(maxDuration, duration);
}
public double getAverage() {
return requestCount > 0 ? (double) totalDuration / requestCount : 0;
}
public long getMin() {
return minDuration == Long.MAX_VALUE ? 0 : minDuration;
}
public long getMax() {
return maxDuration;
}
public long getCount() {
return requestCount;
}
}
}
参数验证拦截器
import org.springframework.util.StringUtils;
public class ValidationInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 验证请求参数
String[] requiredParams = getRequiredParams(request.getRequestURI());
for (String param : requiredParams) {
String value = request.getParameter(param);
if (!StringUtils.hasText(value)) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.getWriter().write("{\"error\":\"Missing required parameter: " + param + "\"}");
return false;
}
}
// 验证请求体(JSON)
if (isJsonRequest(request)) {
String requestBody = getRequestBody(request);
if (!isValidJson(requestBody)) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.getWriter().write("{\"error\":\"Invalid JSON format\"}");
return false;
}
}
return true;
}
private String[] getRequiredParams(String uri) {
// 根据URI返回必需参数
if (uri.contains("/user/create")) {
return new String[]{
"username", "email"};
} else if (uri.contains("/order/create")) {
return new String[]{
"productId", "quantity"};
}
return new String[]{
};
}
private boolean isJsonRequest(HttpServletRequest request) {
String contentType = request.getContentType();
return contentType != null && contentType.contains("application/json");
}
private String getRequestBody(HttpServletRequest request) throws Exception {
StringBuilder sb = new StringBuilder();
String line;
try (java.io.BufferedReader reader = request.getReader()) {
while ((line = reader.readLine()) != null) {
sb.append(line);
}
}
return sb.toString();
}
private boolean isValidJson(String json) {
try {
// 简单的JSON验证
if (json == null || json.trim().isEmpty()) {
return false;
}
return json.trim().startsWith("{") && json.trim().endsWith("}");
} catch (Exception e) {
return false;
}
}
}
CORS拦截器
public class CorsInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 设置CORS头
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, PATCH");
response.setHeader("Access-Control-Allow-Headers",
"Content-Type, Authorization, X-Requested-With, X-Admin-Token");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Credentials", "true");
// 处理预检请求
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
return false; // 阻止后续处理
}
return true;
}
}
拦截器链管理
拦截器执行顺序
在Spring Boot中,拦截器的执行顺序非常重要,可以通过以下方式控制:
// 在配置类中按添加顺序执行
@Configuration
public class OrderedInterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 第一个执行
registry.addInterceptor(new FirstInterceptor())
.addPathPatterns("/**");
// 第二个执行
registry.addInterceptor(new SecondInterceptor())
.addPathPatterns("/**");
// 第三个执行
registry.addInterceptor(new ThirdInterceptor())
.addPathPatterns("/**");
}
}
条件拦截器
public class ConditionalInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 根据条件决定是否执行
if (shouldIntercept(request)) {
// 执行拦截逻辑
System.out.println("条件拦截器执行: " + request.getRequestURI());
return true;
}
return true; // 不拦截,继续执行
}
private boolean shouldIntercept(HttpServletRequest request) {
String uri = request.getRequestURI();
String method = request.getMethod();
// 根据URI和方法判断是否需要拦截
return uri.startsWith("/api/") && "POST".equals(method);
}
}
高级拦截器应用
限流拦截器
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public class RateLimitInterceptor implements HandlerInterceptor {
private final ConcurrentHashMap<String, AtomicInteger> requestCounters = new ConcurrentHashMap<>();
private final long windowSize = 60000; // 1分钟窗口
private final int maxRequests = 100; // 每分钟最大请求数
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String clientIP = getClientIP(request);
long currentTime = System.currentTimeMillis();
String key = clientIP + "_" + (currentTime / windowSize);
AtomicInteger counter = requestCounters.computeIfAbsent(key, k -> new AtomicInteger(0));
int currentCount = counter.incrementAndGet();
if (currentCount > maxRequests) {
response.setStatus(HttpServletResponse.SC_TOO_MANY_REQUESTS);
response.getWriter().write("{\"error\":\"Rate limit exceeded\"}");
return false;
}
// 清理过期的计数器
cleanExpiredCounters(currentTime);
return true;
}
private String getClientIP(HttpServletRequest request) {
String xForwardedFor = request.getHeader("X-Forwarded-For");
if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
return xForwardedFor.split(",")[0].trim();
}
String xRealIP = request.getHeader("X-Real-IP");
if (xRealIP != null && !xRealIP.isEmpty()) {
return xRealIP;
}
return request.getRemoteAddr();
}
private void cleanExpiredCounters(long currentTime) {
long cutoffTime = (currentTime / windowSize) - 2; // 保留2个窗口的数据
requestCounters.entrySet().removeIf(entry -> {
String[] parts = entry.getKey().split("_");
if (parts.length == 2) {
try {
long window = Long.parseLong(parts[1]);
return window < cutoffTime;
} catch (NumberFormatException e) {
return true;
}
}
return false;
});
}
}
缓存拦截器
public class CacheInterceptor implements HandlerInterceptor {
private final ConcurrentHashMap<String, CachedResponse> cache = new ConcurrentHashMap<>();
private final long cacheTimeout = 300000; // 5分钟
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String cacheKey = generateCacheKey(request);
CachedResponse cached = cache.get(cacheKey);
if (cached != null && !cached.isExpired()) {
// 返回缓存的响应
cached.writeTo(response);
return false; // 阻止后续处理
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
String cacheKey = generateCacheKey(request);
if (response.getStatus() == 200) {
// 缓存响应
CachedResponse cachedResponse = new CachedResponse(response);
cache.put(cacheKey, cachedResponse);
}
}
private String generateCacheKey(HttpServletRequest request) {
return request.getMethod() + "_" + request.getRequestURI() +
"_" + request.getQueryString();
}
private static class CachedResponse {
private final byte[] content;
private final int status;
private final java.util.Map<String, String> headers;
private final long timestamp;
public CachedResponse(HttpServletResponse response) {
// 这里需要捕获响应内容,实际实现会更复杂
this.status = response.getStatus();
this.headers = new java.util.HashMap<>();
response.getHeaderNames().forEach(name ->
headers.put(name, response.getHeader(name)));
this.timestamp = System.currentTimeMillis();
this.content = new byte[0]; // 简化示例
}
public boolean isExpired() {
return System.currentTimeMillis() - timestamp > 300000; // 5分钟
}
public void writeTo(HttpServletResponse response) throws Exception {
response.setStatus(status);
headers.forEach(response::setHeader);
// response.getOutputStream().write(content);
}
}
}
数据脱敏拦截器
public class DataMaskingInterceptor implements HandlerInterceptor {
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
if (modelAndView != null && modelAndView.getModel() != null) {
// 对模型数据进行脱敏处理
modelAndView.getModel().forEach((key, value) -> {
if (value instanceof java.util.Map) {
maskSensitiveData((java.util.Map<String, Object>) value);
} else if (value instanceof java.util.List) {
maskSensitiveDataInList((java.util.List<Object>) value);
}
});
}
}
private void maskSensitiveData(java.util.Map<String, Object> data) {
data.replaceAll((key, value) -> {
if (isSensitiveField(key)) {
return maskValue(value);
}
return value;
});
}
private void maskSensitiveDataInList(java.util.List<Object> list) {
for (int i = 0; i < list.size(); i++) {
Object item = list.get(i);
if (item instanceof java.util.Map) {
maskSensitiveData((java.util.Map<String, Object>) item);
}
}
}
private boolean isSensitiveField(String fieldName) {
return fieldName.toLowerCase().contains("password") ||
fieldName.toLowerCase().contains("phone") ||
fieldName.toLowerCase().contains("id_card") ||
fieldName.toLowerCase().contains("email");
}
private Object maskValue(Object value) {
if (value instanceof String) {
String str = (String) value;
if (str.length() <= 4) {
return str.replaceAll(".", "*");
} else {
return str.substring(0, 2) + "****" + str.substring(str.length() - 2);
}
}
return "***MASKED***";
}
}
拦截器与Spring Security集成
Spring Security拦截器链
@Configuration
@EnableWebSecurity
public class SecurityInterceptorConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(securityInterceptor(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public CustomSecurityInterceptor securityInterceptor() {
return new CustomSecurityInterceptor();
}
}
自定义安全拦截器
public class CustomSecurityInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
String jwtToken = token.substring(7);
try {
// 验证JWT token
if (isValidToken(jwtToken)) {
// 设置认证信息到SecurityContext
setAuthentication(jwtToken);
}
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
}
return true;
}
private boolean isValidToken(String token) {
// JWT验证逻辑
return true; // 简化示例
}
private void setAuthentication(String token) {
// 设置Spring Security认证信息
org.springframework.security.core.Authentication auth =
new org.springframework.security.authentication.UsernamePasswordAuthenticationToken(
"user", null, java.util.Collections.emptyList());
org.springframework.security.core.context.SecurityContextHolder.getContext()
.setAuthentication(auth);
}
}
拦截器性能优化
异步拦截器
public class AsyncInterceptor implements AsyncHandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (request.isAsyncStarted()) {
// 异步请求处理
request.setAttribute("asyncStartTime", System.currentTimeMillis());
}
return true;
}
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
System.out.println("异步处理开始");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
if (request.getAttribute("asyncStartTime") != null) {
long startTime = (Long) request.getAttribute("asyncStartTime");
long duration = System.currentTimeMillis() - startTime;
System.out.println("异步请求处理耗时: " + duration + "ms");
}
}
}
拦截器缓存优化
@Component
public class CachedInterceptor implements HandlerInterceptor {
private final com.github.benmanes.caffeine.cache.Cache<String, Boolean> permissionCache;
public CachedInterceptor() {
this.permissionCache = com.github.benmanes.caffeine.cache.Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(java.time.Duration.ofMinutes(10))
.build(this::checkPermission);
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String resource = request.getRequestURI();
String token = request.getHeader("Authorization");
if (token != null && permissionCache.get(resource)) {
return true;
}
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
return false;
}
private Boolean checkPermission(String resource) {
// 权限检查逻辑
return true; // 简化示例
}
}
拦截器测试
单元测试
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest
class InterceptorTest {
@Autowired
private MockMvc mockMvc;
@Test
void testCustomInterceptor() throws Exception {
mockMvc.perform(get("/api/test")
.header("X-Admin-Token", "admin-secret-token"))
.andExpect(status().isOk());
}
@Test
void testUnauthorizedAccess() throws Exception {
mockMvc.perform(get("/admin/protected"))
.andExpect(status().isUnauthorized());
}
}
集成测试
@SpringBootTest
@AutoConfigureTestDatabase
class InterceptorIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
void testRateLimitInterceptor() {
// 发送多个请求测试限流
for (int i = 0; i < 150; i++) {
ResponseEntity<String> response = restTemplate.getForEntity("/api/test", String.class);
if (i >= 100) {
// 超过限流应该返回429
assertEquals(HttpStatus.TOO_MANY_REQUESTS, response.getStatusCode());
}
}
}
}
实际应用场景
API网关拦截器
public class ApiGatewayInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// API版本控制
String apiVersion = request.getHeader("API-Version");
if (apiVersion == null) {
apiVersion = "v1"; // 默认版本
}
// API限流
if (!isWithinRateLimit(request)) {
response.setStatus(HttpServletResponse.SC_TOO_MANY_REQUESTS);
response.getWriter().write("{\"error\":\"API rate limit exceeded\"}");
return false;
}
// API认证
if (!isValidApiKey(request)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("{\"error\":\"Invalid API key\"}");
return false;
}
return true;
}
private boolean isWithinRateLimit(HttpServletRequest request) {
// 限流逻辑
return true; // 简化示例
}
private boolean isValidApiKey(HttpServletRequest request) {
String apiKey = request.getHeader("X-API-Key");
// API密钥验证逻辑
return apiKey != null && apiKey.length() > 10;
}
}
多租户拦截器
public class TenantInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String tenantId = request.getHeader("X-Tenant-ID");
if (tenantId == null || tenantId.trim().isEmpty()) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.getWriter().write("{\"error\":\"Tenant ID is required\"}");
return false;
}
// 设置租户上下文
TenantContext.setCurrentTenant(tenantId);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
// 清理租户上下文
TenantContext.clear();
}
}
class TenantContext {
private static final ThreadLocal<String> currentTenant = new ThreadLocal<>();
public static void setCurrentTenant(String tenantId) {
currentTenant.set(tenantId);
}
public static String getCurrentTenant() {
return currentTenant.get();
}
public static void clear() {
currentTenant.remove();
}
}
最佳实践和注意事项
性能考虑
- 避免在拦截器中执行耗时操作
- 使用缓存减少重复计算
- 合理设置拦截器执行顺序
- 及时清理资源
安全考虑
- 验证输入参数的安全性
- 防止敏感信息泄露
- 实现适当的错误处理
- 使用HTTPS传输
调试和监控
// 添加拦截器执行时间监控
public class MonitoringInterceptor implements HandlerInterceptor {
private final io.micrometer.core.instrument.MeterRegistry meterRegistry;
public MonitoringInterceptor(io.micrometer.core.instrument.MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
request.setAttribute("startTime", System.currentTimeMillis());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
Long startTime = (Long) request.getAttribute("startTime");
if (startTime != null) {
long duration = System.currentTimeMillis() - startTime;
io.micrometer.core.instrument.Timer.Sample sample =
io.micrometer.core.instrument.Timer.start(meterRegistry);
sample.stop(io.micrometer.core.instrument.Timer.builder("interceptor.execution.time")
.tag("interceptor", this.getClass().getSimpleName())
.register(meterRegistry));
}
}
}
总结
Spring Boot拦截器是构建Web应用的重要组件,通过合理使用拦截器可以实现请求预处理、安全控制、日志记录、性能监控等多种功能。在实际开发中,需要根据具体需求选择合适的拦截器实现方式,并注意性能优化和安全考虑,以构建高质量的Web应用程序。
关于作者
🌟 我是suxiaoxiang,一位热爱技术的开发者
💡 专注于Java生态和前沿技术分享
🚀 持续输出高质量技术内容
如果这篇文章对你有帮助,请支持一下:
👍 点赞
⭐ 收藏
👀 关注
您的支持是我持续创作的动力!感谢每一位读者的关注与认可!