spring Interceptor小应用

本文介绍了一种使用拦截器实现性能监控的方法,通过记录请求处理时间来定位慢请求,并提出了解决多线程环境下时间记录问题的方案。此外,还讨论了如何利用拦截器进行登录检测,确保用户在访问特定资源前已完成登录。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

性能监控

如记录一下请求的处理时间,得到一些慢请求(如处理时间超过500毫秒),从而进行性能改进,一般的反向代理服务器如apache都具有这个功能,但此处我们演示一下使用拦截器怎么实现。

 

实现分析:

1、在进入处理器之前记录开始时间,即在拦截器的preHandle记录开始时间;

2、在结束请求处理之后记录结束时间,即在拦截器的afterCompletion记录结束实现,并用结束时间-开始时间得到这次请求的处理时间。

 

问题:

我们的拦截器是单例,因此不管用户请求多少次都只有一个拦截器实现,即线程不安全,那我们应该怎么记录时间呢?

解决方案是使用ThreadLocal,它是线程绑定的变量,提供线程局部变量(一个线程一个ThreadLocal,A线程的ThreadLocal只能看到A线程的ThreadLocal,不能看到B线程的ThreadLocal)。

package cn.javass.chapter5.web.interceptor;
public class StopWatchHandlerInterceptor extends HandlerInterceptorAdapter {
    private NamedThreadLocal<Long>  startTimeThreadLocal = 
new NamedThreadLocal<Long>("StopWatch-StartTime");
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 
Object handler) throws Exception {
        long beginTime = System.currentTimeMillis();//1、开始时间
        startTimeThreadLocal.set(beginTime);//线程绑定变量(该数据只有当前请求的线程可见)
        return true;//继续流程
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, 
Object handler, Exception ex) throws Exception {
        long endTime = System.currentTimeMillis();//2、结束时间
        long beginTime = startTimeThreadLocal.get();//得到线程绑定的局部变量(开始时间)
        long consumeTime = endTime - beginTime;//3、消耗的时间
        if(consumeTime > 500) {//此处认为处理时间超过500毫秒的请求为慢请求
            //TODO 记录到日志文件
            System.out.println(
String.format("%s consume %d millis", request.getRequestURI(), consumeTime));
        }        
    }
}

 

登录检测

在访问某些资源时(如订单页面),需要用户登录后才能查看,因此需要进行登录检测。

 

流程:

1、访问需要登录的资源时,由拦截器重定向到登录页面;

2、如果访问的是登录页面,拦截器不应该拦截;

3、用户登录成功后,往cookie/session添加登录成功的标识(如用户编号);

4、下次请求时,拦截器通过判断cookie/session中是否有该标识来决定继续流程还是到登录页面;

5、在此拦截器还应该允许游客访问的资源。

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 
Object handler) throws Exception {
    //1、请求到登录页面 放行
    if(request.getServletPath().startsWith(loginUrl)) {
        return true;
    }
        
    //2、TODO 比如退出、首页等页面无需登录,即此处要放行 允许游客的请求
        
    //3、如果用户已经登录 放行  
    if(request.getSession().getAttribute("username") != null) {
        //更好的实现方式的使用cookie
        return true;
    }
        
    //4、非法请求 即这些请求需要登录后才能访问
    //重定向到登录页面
    response.sendRedirect(request.getContextPath() + loginUrl);
    return false;
}

 

提示:推荐能使用servlet规范中的过滤器Filter实现的功能就用Filter实现,因为HandlerInteceptor只有在Spring Web MVC环境下才能使用,因此Filter是最通用的、最先应该使用的。如登录这种拦截器最好使用Filter来实现。

 

from:http://jinnianshilongnian.iteye.com/blog/1670856

### Spring 框架中的拦截器和过滤器 #### 区别 在Spring框架中,拦截器(Interceptor)和过滤器(Filter)虽然都能用于处理请求,但是二者存在显著差异。 - **作用范围** - 过滤器是在Servlet容器级别工作的组件,可以应用于任何Web应用程序资源的访问前后的处理过程。这意味着它不仅限于Spring MVC控制器方法调用前后的行为控制[^1]。 - 拦截器则属于Spring MVC的一部分,在DispatcherServlet初始化之后生效,主要用于增强Controller层的功能,比如权限验证、日志记录等操作,仅针对进入Spring MVC流程内的请求有效[^2]。 - **实现机制** - 过滤器依赖于Servlet API提供的功能来执行任务,其底层通过函数回调的方式工作;而拦截器是基于Java反射技术(即动态代理),允许更灵活地定义预处理逻辑和后置处理逻辑[^3]。 #### 使用方法 ##### 过滤器配置与使用 要创建自定义过滤器,需继承`javax.servlet.Filter`接口并重写其中的方法: ```java public class MyCustomFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // Pre-processing logic here chain.doFilter(request,response); // Pass control to next element in the filter chain. // Post-processing logic here } @Override public void destroy() {} } ``` 接着可以在web.xml文件里注册该过滤器或将其实现为@Component并通过注解形式自动装配到应用上下文中。 ##### 拦截器配置与使用 对于拦截器来说,通常会扩展`HandlerInterceptorAdapter`类或直接实现`HandlerInterceptor`接口: ```java import org.springframework.web.servlet.HandlerInterceptor; 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){ // Logic before controller method execution return true; // Return false will stop further processing of this request } @Override public void postHandle(HttpServletRequest request,HttpServletResponse response,Object handler, ModelAndView modelAndView){ // Logic after controller method but before view rendering } @Override public void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler, Exception ex){ // Cleanup work or logging can be done here } } ``` 为了使上述拦截器生效,还需要将其添加至Spring MVC配置中,可以通过XML方式或者借助@Configuration类完成此操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值