spring中過(guò)濾器(filter)、攔截器(interceptor)和切面(aop)的執(zhí)行順序

轉(zhuǎn)載自:https://d.we90s.net/article/23

三者區(qū)別

Filter(過(guò)濾器)

過(guò)濾器是服務(wù)端的一個(gè)組件,是基于servlet實(shí)現(xiàn)從客戶端訪問(wèn)服務(wù)端web資源的一種攔截機(jī)制,對(duì)請(qǐng)求request和響應(yīng)response都進(jìn)行過(guò)濾,依賴于serverlet容器,使用時(shí),實(shí)現(xiàn)Filter接口,在web.xml里配置對(duì)應(yīng)的class還有mapping-url。

//@Component
public class TimeFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) {
        System.out.println("過(guò)濾器初始化");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("過(guò)濾器執(zhí)行了");
        long start2 = System.currentTimeMillis();
        filterChain.doFilter(servletRequest, servletResponse);
        long time = System.currentTimeMillis() - start2;
        System.out.println("過(guò)濾器執(zhí)行的時(shí)間是 :" + time);
        System.out.println("過(guò)濾器執(zhí)行結(jié)束");
    }

    @Override
    public void destroy() {
        System.out.println("過(guò)濾器銷毀了");
    }
}

interceptor(攔截器)

攔截器,顧名思義,它的作用就是攔截,這個(gè)要和過(guò)濾器區(qū)分開(kāi),過(guò)濾器依賴serverlet容器,獲取request和response處理,是基于函數(shù)回調(diào)(框架本身調(diào)用的,它會(huì)遍歷所有注冊(cè)的過(guò)濾器,并且一一調(diào)用doFilter()),簡(jiǎn)單說(shuō)就是“去取你想取的”。攔截器是通過(guò)Java反射機(jī)制來(lái)攔截web請(qǐng)求,是“拒你想拒絕的”,它只攔截web請(qǐng)求,但不攔截靜態(tài)資源。

攔截器,在AOP中用于在某個(gè)方法或字段被訪問(wèn)之前,進(jìn)行攔截,然后在之前或之后加入某些操作。攔截是AOP的一種實(shí)現(xiàn)策略。

@Component
public class TimeInterceptor implements HandlerInterceptor {

    // 在controller調(diào)用之前調(diào)用,通過(guò)返回true或者false決定是否進(jìn)入Controller層
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("preHandle");
        System.out.println(((HandlerMethod)handler).getBean().getClass().getName());
        System.out.println(((HandlerMethod)handler).getMethod().getName());
        request.setAttribute("startTime", new Date().getTime());
        return true;
    }
 
    // 在請(qǐng)求進(jìn)入控制層之后調(diào)用,但是在處理請(qǐng)求拋出異常時(shí)不會(huì)調(diào)用
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle");
        Long start = (Long)request.getAttribute("startTime");
        System.out.println("time interceptor 耗時(shí):"+ (new Date().getTime() - start));
    }
 
    // 在請(qǐng)求處理完成之后,也就是在DispatherServlet渲染了視圖之后執(zhí)行,也就是說(shuō)這個(gè)方法必定是執(zhí)行,包含異常信息,它的主要作用就是清理資源
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("afterCompletion");
        Long start = (Long) request.getAttribute("startTime");
        System.out.println("time interceptor 耗時(shí):"+ (new Date().getTime() - start));
        System.out.println("ex is "+ex);
    }
 
}

Aspect(切片)

相比過(guò)濾器,攔截器能夠知道用戶發(fā)出的請(qǐng)求最終被哪個(gè)控制器處理,但是攔截器還有一個(gè)明顯的不足,即不能夠獲取request的參數(shù)以及控制器處理之后的response。(注意 ,我曾經(jīng)試過(guò),獲得被攔截方法的一些參數(shù),但是通過(guò)methodParaters無(wú)法獲得,后來(lái)只能通過(guò)request.getParameter(..)來(lái)獲?。┧跃陀辛饲衅挠梦渲亓恕?/p>

@Aspect
@Component
public class TimeAspect {

    @Around("execution(* com.wtzhou.security.controller.UserController.*(..))")
//    @After("")
//    @Before("")
//    @AfterThrowing()
//    @AfterReturning()
    public Object handlerControllerMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object[] args = proceedingJoinPoint.getArgs();
        for (Object arg : args) {
            out.println("請(qǐng)求參數(shù)為:"+arg);
        }
        out.println("TimeAspect 切片開(kāi)始執(zhí)行");
        long start = currentTimeMillis();
        Object proceed = proceedingJoinPoint.proceed();
        out.println("切片執(zhí)行耗時(shí):" + (currentTimeMillis() - start));
        out.println("切片執(zhí)行結(jié)束!");
        return proceed;
    }
}

總結(jié)

【Filter與Interceptor的區(qū)別】

  • filter基于filter接口中的doFilter回調(diào)函數(shù),interceptor則基于Java本身的反射機(jī)制;
  • filter是依賴于servlet容器的,沒(méi)有servlet容器就無(wú)法回調(diào)doFilter方法,而interceptor與servlet無(wú)關(guān);
  • filter的過(guò)濾范圍比interceptor大,filter除了過(guò)濾請(qǐng)求外通過(guò)通配符可以保護(hù)頁(yè)面、圖片、文件等,而interceptor只能過(guò)濾請(qǐng)求,只對(duì)action起作用,在action之前開(kāi)始,在action完成后結(jié)束(如被攔截,不執(zhí)行action);
  • 在action的生命周期中,攔截器可以被多次調(diào)用,而過(guò)濾器只能在容器初始化時(shí)被調(diào)用一次。

【Interceptor 與spring AOP的區(qū)別】

  • spring Interceptor也是一種aop思想,我們這里面的spring AOP主要是講aop應(yīng)用,interceptor 的使用場(chǎng)合比aop小很多,顧名思義,它是攔截一些action請(qǐng)求,但是比aop使用起來(lái)簡(jiǎn)便;
  • 程序執(zhí)行的順序是先進(jìn)過(guò)濾器,再進(jìn)攔截器,最后進(jìn)切面;
  • Interceptor可以阻止代碼執(zhí)行下去,當(dāng)preHandle返回false,那么這個(gè)請(qǐng)求就到此結(jié)束,真正的被攔截了,但是aop不能,它只是單純的切入添加操作;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容