当前位置: 首页 > news >正文

拦截器与过滤器链机制

文章目录

  • 拦截器与过滤器链机制
  • 🎯 一、Filter 与 Interceptor 架构对比
    • 💡 定位与作用域差异
    • 🏗️ 执行流程架构
  • 🔄 二、DispatcherServlet 请求链路拦截点
    • 🔧 核心拦截点源码分析
    • 📊 HandlerExecutionChain 拦截器管理
  • ⏱️ 三、拦截器方法调用顺序深度解析
    • 🔄 多拦截器执行时序
    • ⚡ 拦截器配置与顺序控制
    • 🔍 拦截器执行监控
  • 🛡️ 四、实战:企业级接口鉴权拦截器
    • 💡 JWT 认证拦截器实现
    • 🔐 权限控制拦截器
    • 📊 完整的拦截器配置
  • 💡 五、性能优化与监控体系
    • ⚡ 拦截器性能优化
    • 📈 拦截器监控体系
    • 🔧 过滤器与拦截器协作配置

拦截器与过滤器链机制

🎯 一、Filter 与 Interceptor 架构对比

💡 定位与作用域差异

架构层次对比图:

客户端请求
Servlet Filter
Spring Interceptor
Controller
Service
DAO

核心差异对比表:

特性Servlet FilterSpring Interceptor差异分析 / 设计价值
规范层级基于 Servlet 规范(J2EE 标准)属于 Spring MVC 框架扩展层Filter 是底层容器能力,Interceptor 是框架级增强
依赖容器不依赖 Spring 容器,可独立运行完全依赖 Spring 上下文Interceptor 能与 IoC、AOP、事务管理无缝协作
作用范围处理所有 Web 请求(包括静态资源)仅拦截 Spring MVC 控制器请求Filter 更通用,Interceptor 更聚焦业务逻辑
获取 Bean需通过 WebApplicationContextUtils 手动获取可直接 @Autowired 注入Interceptor 更符合 Spring 编程模型
执行顺序在 Interceptor 之前执行在 Filter 之后执行Filter 适合安全、日志类预处理;Interceptor 适合控制层逻辑
异常处理仅能捕获 Servlet 层异常可参与 Spring 异常体系(@ControllerAdviceInterceptor 能实现更细粒度的异常与返回统一化
配置方式web.xml / @WebFilter 注解注册到 WebMvcConfigurerInterceptor 配置更灵活、可按路径精确控制
典型用途编码过滤、XSS 防护、全局安全过滤登录校验、权限验证、操作日志、性能监控可联合使用,形成双层安全与逻辑拦截链

🏗️ 执行流程架构

完整请求处理流水线:

ClientFilter1Filter2DispatcherServletInterceptor1Interceptor2ControllerServiceHTTP Request过滤器前置处理chain.doFilter()进入Spring MVCpreHandle()preHandle()执行控制器业务逻辑返回结果返回ModelAndViewpostHandle()postHandle()完成处理返回响应过滤器后置处理后置处理HTTP ResponseafterCompletion() 异步执行ClientFilter1Filter2DispatcherServletInterceptor1Interceptor2ControllerService

🔄 二、DispatcherServlet 请求链路拦截点

🔧 核心拦截点源码分析

DispatcherServlet doDispatch 方法拦截点:

public class DispatcherServlet extends FrameworkServlet {protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HandlerExecutionChain mappedHandler = null;ModelAndView mv = null;Exception dispatchException = null;try {// 1. 文件上传检查点processedRequest = checkMultipart(request);// 2. 获取处理器执行链(包含拦截器)mappedHandler = getHandler(processedRequest);if (mappedHandler == null) {noHandlerFound(processedRequest, response);return;}// 3. 获取处理器适配器HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// 📍 拦截点1: 执行所有拦截器的preHandle方法if (!mappedHandler.applyPreHandle(processedRequest, response)) {return; // 如果任一拦截器返回false,直接返回}// 4. 实际执行处理器(Controller方法)mv = ha.handle(processedRequest, response, mappedHandler.getHandler());// 5. 应用默认视图名applyDefaultViewName(processedRequest, mv);// 📍 拦截点2: 执行所有拦截器的postHandle方法(逆序)mappedHandler.applyPostHandle(processedRequest, response, mv);} catch (Exception ex) {dispatchException = ex;} finally {// 📍 拦截点3: 执行所有拦截器的afterCompletion方法if (mappedHandler != null) {mappedHandler.triggerAfterCompletion(processedRequest, response, dispatchException);}}}
}

📊 HandlerExecutionChain 拦截器管理

拦截器链执行核心逻辑:

public class HandlerExecutionChain {private final Object handler;private final HandlerInterceptor[] interceptors;private int interceptorIndex = -1;/*** 执行preHandle拦截*/boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {for (int i = 0; i < this.interceptors.length; i++) {HandlerInterceptor interceptor = this.interceptors[i];if (!interceptor.preHandle(request, response, this.handler)) {// 拦截器返回false,触发已完成拦截器的afterCompletiontriggerAfterCompletion(request, response, null);return false;}this.interceptorIndex = i; // 记录最后一个成功的拦截器索引}return true;}/*** 执行postHandle拦截(逆序)*/void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView modelAndView) throws Exception {for (int i = this.interceptors.length - 1; i >= 0; i--) {HandlerInterceptor interceptor = this.interceptors[i];interceptor.postHandle(request, response, this.handler, modelAndView);}}/*** 执行afterCompletion拦截*/void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {for (int i = this.interceptorIndex; i >= 0; i--) {HandlerInterceptor interceptor = this.interceptors[i];try {interceptor.afterCompletion(request, response, this.handler, ex);} catch (Throwable ex2) {logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);}}}
}

⏱️ 三、拦截器方法调用顺序深度解析

🔄 多拦截器执行时序

完整拦截器调用时序图:

DispatcherServletInterceptor1Interceptor2Interceptor3ControllerView第一阶段:preHandle 顺序执行preHandle()truepreHandle()truepreHandle()true第二阶段:Controller执行执行业务逻辑返回结果第三阶段:postHandle 逆序执行postHandle()postHandle()postHandle()第四阶段:视图渲染render()完成第五阶段:afterCompletion 逆序执行afterCompletion()afterCompletion()afterCompletion()DispatcherServletInterceptor1Interceptor2Interceptor3ControllerView

⚡ 拦截器配置与顺序控制

精细化拦截器配置:

@Configuration
@Slf4j
public class InterceptorConfiguration implements WebMvcConfigurer {@Autowiredprivate LoggingInterceptor loggingInterceptor;@Autowiredprivate AuthInterceptor authInterceptor;@Autowiredprivate PermissionInterceptor permissionInterceptor;@Autowiredprivate RateLimitInterceptor rateLimitInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 1. 日志拦截器(最外层,最先执行)registry.addInterceptor(loggingInterceptor).order(Ordered.HIGHEST_PRECEDENCE) // 最高优先级.addPathPatterns("/api/**").excludePathPatterns("/api/health", "/api/metrics").addPathPatterns("/admin/**");// 2. 限流拦截器registry.addInterceptor(rateLimitInterceptor).order(Ordered.HIGHEST_PRECEDENCE + 10).addPathPatterns("/api/**").excludePathPatterns("/api/static/**");// 3. 认证拦截器registry.addInterceptor(authInterceptor).order(Ordered.HIGHEST_PRECEDENCE + 20).addPathPatterns("/api/**").excludePathPatterns("/api/public/**", "/api/auth/login");// 4. 权限拦截器(最内层,最后执行)registry.addInterceptor(permissionInterceptor).order(Ordered.LOWEST_PRECEDENCE) // 最低优先级.addPathPatterns("/api/**", "/admin/**").excludePathPatterns("/api/public/**");}
}

🔍 拦截器执行监控

拦截器执行跟踪工具:

@Component
@Slf4j
public class InterceptorExecutionTracer {private static final ThreadLocal<InterceptorTrace> traceHolder = new ThreadLocal<>();/*** 开始跟踪*/public void startTrace(HttpServletRequest request) {InterceptorTrace trace = new InterceptorTrace();trace.setStartTime(System.currentTimeMillis());trace.setRequestPath(request.getRequestURI());traceHolder.set(trace);}/*** 记录拦截器执行*/public void recordInterceptorExecution(String interceptorName, String phase, long duration) {InterceptorTrace trace = traceHolder.get();if (trace != null) {trace.addExecutionRecord(interceptorName, phase, duration);}}/*** 完成跟踪并输出报告*/public void completeTrace() {InterceptorTrace trace = traceHolder.get();if (trace != null) {log.info("拦截器执行跟踪报告: {}", trace.generateReport());traceHolder.remove();}}@Datapublic static class InterceptorTrace {private long startTime;private String requestPath;private List<ExecutionRecord> records = new ArrayList<>();public void addExecutionRecord(String interceptorName, String phase, long duration) {records.add(new ExecutionRecord(interceptorName, phase, duration));}public String generateReport() {StringBuilder report = new StringBuilder();report.append("路径: ").append(requestPath).append("\n");report.append("总耗时: ").append(System.currentTimeMillis() - startTime).append("ms\n");report.append("拦截器执行详情:\n");for (ExecutionRecord record : records) {report.append(String.format("  %s - %s: %dms\n", record.interceptorName, record.phase, record.duration));}return report.toString();}}@Data@AllArgsConstructorpublic static class ExecutionRecord {private String interceptorName;private String phase;private long duration;}
}

🛡️ 四、实战:企业级接口鉴权拦截器

💡 JWT 认证拦截器实现

完整的认证拦截器实现:

@Component
@Slf4j
public class JwtAuthenticationInterceptor implements HandlerInterceptor {@Autowiredprivate JwtTokenProvider tokenProvider;@Autowiredprivate UserService userService;private static final String AUTH_HEADER = "Authorization";private static final String BEARER_PREFIX = "Bearer ";private static final String USER_ATTR = "currentUser";@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1. 检查是否是需要跳过的路径if (shouldSkipAuth(request)) {return true;}// 2. 提取并验证TokenString token = extractToken(request);if (token == null) {sendUnauthorizedResponse(response, "缺少认证令牌");return false;}// 3. 验证Token有效性if (!tokenProvider.validateToken(token)) {sendUnauthorizedResponse(response, "令牌无效或已过期");return false;}// 4. 解析用户信息并设置到请求上下文中try {Authentication authentication = createAuthentication(token);SecurityContextHolder.getContext().setAuthentication(authentication);// 5. 将用户信息设置到请求属性中UserDetails userDetails = (UserDetails) authentication.getPrincipal();request.setAttribute(USER_ATTR, userDetails);log.debug("用户认证成功: {} - {}", userDetails.getUsername(), request.getRequestURI());return true;} catch (Exception ex) {log.error("令牌解析失败", ex);sendUnauthorizedResponse(response, "令牌解析失败");return false;}}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {// 清理安全上下文,防止内存泄漏SecurityContextHolder.clearContext();}/*** 提取JWT令牌*/private String extractToken(HttpServletRequest request) {String bearerToken = request.getHeader(AUTH_HEADER);if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(BEARER_PREFIX)) {return bearerToken.substring(BEARER_PREFIX.length());}return null;}/*** 检查是否需要跳过认证*/private boolean shouldSkipAuth(HttpServletRequest request) {String path = request.getRequestURI();// 1. 检查白名单路径List<String> whiteList = Arrays.asList("/api/public/", "/api/auth/login", "/api/auth/register", "/api/docs", "/swagger-ui", "/v3/api-docs");if (whiteList.stream().anyMatch(path::startsWith)) {return true;}// 2. 检查注解配置if (handlerRequiresNoAuth(handler)) {return true;}return false;}/*** 检查处理器上的注解*/private boolean handlerRequiresNoAuth(Object handler) {if (handler instanceof HandlerMethod) {HandlerMethod handlerMethod = (HandlerMethod) handler;// 检查方法上的@PublicApi注解if (handlerMethod.getMethodAnnotation(PublicApi.class) != null) {return true;}// 检查类上的@PublicApi注解if (handlerMethod.getBeanType().isAnnotationPresent(PublicApi.class)) {return true;}}return false;}/*** 创建认证信息*/private Authentication createAuthentication(String token) {String username = tokenProvider.getUsernameFromToken(token);UserDetails userDetails = userService.loadUserByUsername(username);return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());}/*** 发送未认证响应*/private void sendUnauthorizedResponse(HttpServletResponse response, String message) throws IOException {response.setStatus(HttpStatus.UNAUTHORIZED.value());response.setContentType(MediaType.APPLICATION_JSON_VALUE);Map<String, Object> errorResponse = new HashMap<>();errorResponse.put("success", false);errorResponse.put("code", "UNAUTHORIZED");errorResponse.put("message", message);errorResponse.put("timestamp", System.currentTimeMillis());ObjectMapper mapper = new ObjectMapper();response.getWriter().write(mapper.writeValueAsString(errorResponse));}
}

🔐 权限控制拦截器

基于注解的权限控制:

@Component  
@Slf4j
public class PermissionInterceptor implements HandlerInterceptor {@Autowiredprivate PermissionService permissionService;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {if (!(handler instanceof HandlerMethod)) {return true;}HandlerMethod handlerMethod = (HandlerMethod) handler;// 1. 检查权限注解RequirePermission requirePermission = handlerMethod.getMethodAnnotation(RequirePermission.class);if (requirePermission == null) {return true; // 没有权限要求,直接放行}// 2. 获取当前用户Authentication authentication = SecurityContextHolder.getContext().getAuthentication();if (authentication == null || !authentication.isAuthenticated()) {sendForbiddenResponse(response, "用户未认证");return false;}// 3. 验证权限String[] requiredPermissions = requirePermission.value();Logical logical = requirePermission.logical();boolean hasPermission = permissionService.hasPermissions(authentication, requiredPermissions, logical);if (!hasPermission) {log.warn("权限不足: 用户={}, 路径={}, 所需权限={}", authentication.getName(), request.getRequestURI(), Arrays.toString(requiredPermissions));sendForbiddenResponse(response, "权限不足");return false;}log.debug("权限验证通过: 用户={}, 路径={}", authentication.getName(), request.getRequestURI());return true;}private void sendForbiddenResponse(HttpServletResponse response, String message) throws IOException {response.setStatus(HttpStatus.FORBIDDEN.value());response.setContentType(MediaType.APPLICATION_JSON_VALUE);Map<String, Object> errorResponse = new HashMap<>();errorResponse.put("success", false);errorResponse.put("code", "FORBIDDEN");errorResponse.put("message", message);errorResponse.put("timestamp", System.currentTimeMillis());ObjectMapper mapper = new ObjectMapper();response.getWriter().write(mapper.writeValueAsString(errorResponse));}
}/*** 权限验证注解*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequirePermission {String[] value() default {};Logical logical() default Logical.AND;
}/*** 逻辑操作枚举*/
public enum Logical {AND, OR
}/*** 公开API注解(跳过认证)*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PublicApi {
}

📊 完整的拦截器配置

生产级拦截器链配置:

@Configuration
@EnableWebMvc
@Slf4j
public class SecurityInterceptorConfig implements WebMvcConfigurer {@Autowiredprivate JwtAuthenticationInterceptor jwtAuthInterceptor;@Autowiredprivate PermissionInterceptor permissionInterceptor;@Autowiredprivate LoggingInterceptor loggingInterceptor;@Autowiredprivate RateLimitInterceptor rateLimitInterceptor;@Autowiredprivate CorsInterceptor corsInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {log.info("配置拦截器链...");// 1. CORS拦截器(最外层)registry.addInterceptor(corsInterceptor).order(Ordered.HIGHEST_PRECEDENCE).addPathPatterns("/**");// 2. 日志拦截器registry.addInterceptor(loggingInterceptor).order(Ordered.HIGHEST_PRECEDENCE + 10).addPathPatterns("/api/**", "/admin/**").excludePathPatterns("/health", "/metrics", "/static/**");// 3. 限流拦截器registry.addInterceptor(rateLimitInterceptor).order(Ordered.HIGHEST_PRECEDENCE + 20).addPathPatterns("/api/**").excludePathPatterns("/api/static/**");// 4. 认证拦截器registry.addInterceptor(jwtAuthInterceptor).order(Ordered.HIGHEST_PRECEDENCE + 30).addPathPatterns("/api/**", "/admin/**").excludePathPatterns("/api/public/**", "/api/auth/**", "/api/docs/**");// 5. 权限拦截器(最内层)registry.addInterceptor(permissionInterceptor).order(Ordered.LOWEST_PRECEDENCE).addPathPatterns("/api/**", "/admin/**").excludePathPatterns("/api/public/**");log.info("拦截器链配置完成");}
}

💡 五、性能优化与监控体系

⚡ 拦截器性能优化

高性能拦截器实现:

@Component
@Slf4j
public class PerformanceOptimizedInterceptor implements HandlerInterceptor {private final ConcurrentMap<String, Boolean> pathCache = new ConcurrentHashMap<>();private final RateLimiter rateLimiter = RateLimiter.create(1000); // 每秒1000次请求@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {long startTime = System.nanoTime();try {// 1. 限流保护if (!rateLimiter.tryAcquire()) {sendTooManyRequestsResponse(response);return false;}// 2. 路径匹配缓存优化String path = request.getRequestURI();Boolean shouldProcess = pathCache.computeIfAbsent(path, this::shouldProcessPath);if (!shouldProcess) {return true; // 跳过处理}// 3. 异步处理耗时操作if (requiresAsyncProcessing(request)) {CompletableFuture.runAsync(() -> processAsync(request));}return true;} finally {long duration = System.nanoTime() - startTime;if (duration > 100_000_000) { // 超过100ms记录警告log.warn("拦截器执行缓慢: {}ms, 路径: {}", duration / 1_000_000, request.getRequestURI());}}}private boolean shouldProcessPath(String path) {// 实现智能路径匹配逻辑return !path.startsWith("/static/") && !path.equals("/health") && !path.contains("websocket");}private boolean requiresAsyncProcessing(HttpServletRequest request) {return request.getRequestURI().contains("/analytics/") ||request.getRequestURI().contains("/monitoring/");}private void processAsync(HttpServletRequest request) {// 异步处理分析、监控等耗时操作try {// 模拟异步处理Thread.sleep(50);log.debug("异步处理完成: {}", request.getRequestURI());} catch (InterruptedException e) {Thread.currentThread().interrupt();}}private void sendTooManyRequestsResponse(HttpServletResponse response) throws IOException {response.setStatus(429);response.setContentType("application/json");response.getWriter().write("{\"error\":\"请求过于频繁\"}");}
}

📈 拦截器监控体系

拦截器监控与指标收集:

@Component
@Slf4j
public class InterceptorMetricsCollector {private final MeterRegistry meterRegistry;private final Map<String, Timer> timerMap = new ConcurrentHashMap<>();private final Map<String, Counter> counterMap = new ConcurrentHashMap<>();public InterceptorMetricsCollector(MeterRegistry meterRegistry) {this.meterRegistry = meterRegistry;}/*** 记录拦截器执行时间*/public void recordInterceptorExecution(String interceptorName, String phase, long duration) {String timerName = "interceptor." + interceptorName + "." + phase;Timer timer = timerMap.computeIfAbsent(timerName, name -> Timer.builder(name).description(interceptorName + " " + phase + "执行时间").register(meterRegistry));timer.record(duration, TimeUnit.MILLISECONDS);}/*** 记录拦截器执行次数*/public void recordInterceptorInvocation(String interceptorName, boolean success) {String status = success ? "success" : "failure";String counterName = "interceptor." + interceptorName + ".invocations";Counter counter = counterMap.computeIfAbsent(counterName + "." + status,name -> Counter.builder(name).description(interceptorName + "调用次数").tag("status", status).register(meterRegistry));counter.increment();}/*** 生成拦截器性能报告*/public Map<String, Object> generateInterceptorReport() {Map<String, Object> report = new HashMap<>();// 收集计时器数据Map<String, Object> timerStats = new HashMap<>();timerMap.forEach((name, timer) -> {Timer.Snapshot snapshot = timer.takeSnapshot();Map<String, Object> stats = new HashMap<>();stats.put("count", snapshot.count());stats.put("mean", snapshot.mean(TimeUnit.MILLISECONDS));stats.put("max", snapshot.max(TimeUnit.MILLISECONDS));timerStats.put(name, stats);});report.put("timers", timerStats);// 收集计数器数据Map<String, Object> counterStats = new HashMap<>();counterMap.forEach((name, counter) -> {counterStats.put(name, counter.count());});report.put("counters", counterStats);return report;}
}/*** 可监控的拦截器基类*/
public abstract class MonitorableInterceptor implements HandlerInterceptor {@Autowiredprivate InterceptorMetricsCollector metricsCollector;private final String interceptorName;protected MonitorableInterceptor() {this.interceptorName = this.getClass().getSimpleName();}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {long startTime = System.currentTimeMillis();boolean success = false;try {success = doPreHandle(request, response, handler);return success;} finally {long duration = System.currentTimeMillis() - startTime;metricsCollector.recordInterceptorExecution(interceptorName, "preHandle", duration);metricsCollector.recordInterceptorInvocation(interceptorName, success);}}protected abstract boolean doPreHandle(HttpServletRequest request, HttpServletResponse response, Object handler);
}

🔧 过滤器与拦截器协作配置

完整的Web安全配置:

@Configuration
@Slf4j
public class WebSecurityConfig {/*** 配置过滤器链*/@Beanpublic FilterRegistrationBean<RequestContextFilter> requestContextFilter() {FilterRegistrationBean<RequestContextFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(new RequestContextFilter());registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);return registrationBean;}/*** 字符编码过滤器*/@Beanpublic FilterRegistrationBean<CharacterEncodingFilter> characterEncodingFilter() {FilterRegistrationBean<CharacterEncodingFilter> registrationBean = new FilterRegistrationBean<>();CharacterEncodingFilter filter = new CharacterEncodingFilter();filter.setEncoding("UTF-8");filter.setForceEncoding(true);registrationBean.setFilter(filter);registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE + 10);registrationBean.addUrlPatterns("/*");return registrationBean;}/*** 请求日志过滤器*/@Beanpublic FilterRegistrationBean<RequestLoggingFilter> requestLoggingFilter() {FilterRegistrationBean<RequestLoggingFilter> registrationBean = new FilterRegistrationBean<>();RequestLoggingFilter filter = new RequestLoggingFilter();registrationBean.setFilter(filter);registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE + 20);registrationBean.addUrlPatterns("/api/*", "/admin/*");return registrationBean;}
}/*** 自定义请求日志过滤器*/
@Slf4j
public class RequestLoggingFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {long startTime = System.currentTimeMillis();HttpServletRequest httpRequest = (HttpServletRequest) request;try {// 前置处理:记录请求开始logRequestStart(httpRequest);chain.doFilter(request, response);} finally {// 后置处理:记录请求完成long duration = System.currentTimeMillis() - startTime;logRequestCompletion(httpRequest, duration);}}private void logRequestStart(HttpServletRequest request) {if (log.isDebugEnabled()) {log.debug("请求开始: {} {} from {}", request.getMethod(), request.getRequestURI(), request.getRemoteAddr());}}private void logRequestCompletion(HttpServletRequest request, long duration) {if (duration > 1000) {log.warn("慢请求: {} {} 耗时 {}ms", request.getMethod(), request.getRequestURI(), duration);} else if (log.isDebugEnabled()) {log.debug("请求完成: {} {} 耗时 {}ms", request.getMethod(), request.getRequestURI(), duration);}}
}
http://www.dtcms.com/a/566812.html

相关文章:

  • wordpress资讯百度搜索推广优化师工作内容
  • 什么是太阳光谱?如何在实验室复现太阳光?
  • 东莞整合网站建设开发网站设计有限公司
  • 如何设置自己的网站怎样上传网站程序
  • 番禺网站开发哪家专业凡科快图登录入口
  • 沈阳建设局网站在线crm网站
  • 温州手机网站制作哪家好wordpress 段间距
  • 常州免费企业网站建设做网站的集群方案
  • 做网站运用的技术宁波网站推广优化公司
  • LeetCode hot100:238 除自身以外数组的乘积:不用除法的巧妙解法
  • 兰州seo网站排名intitlt 山西大同网站建设
  • 襄樊做网站网站设计的能力要求
  • 设计专业知名企业网站上海市开办企业一窗网上服务
  • app建设网站公司注册500万公司每月交税
  • 做个淘宝客网站怎么做免费个人主页注册
  • .net 网站 iis 配置酒店网络营销策略论文
  • 怎么做网站推广电话百度收录网站怎么做
  • asp网站建设实录贵阳网站设计找哪家
  • 新乡做网站优化常德seo排名
  • 苏州 手机网站新一代 网站备案
  • 做个什么样的网站软件的ui设计是什么
  • 中文网站的seo怎么做如何搭建一个简单的网站
  • 品牌网站怎么建立做采购 通常在什么网站看
  • wordpress 5编辑器使用教程南宁seo外包要求
  • 潍坊建设局官方网站建众智业公司简介
  • 阿里云网站备份建设银行国管公积金管理中心网站
  • 贵阳网站制作费用普洱做网站的报价
  • Coze-AI智能体开发平台2-Coze资源
  • 代码随想录 Q70.组合总和 Ⅲ
  • 网站设计常用软件网站开发前期方案