Spring 攔截器實現+后台原理(HandlerInterceptor)


過濾器跟攔截器的區別

spring mvc的攔截器是只攔截controller而不攔截jsp,html 頁面文件的。這就用到過濾器filter了,filter是在servlet前執行的,你也可以理解成過濾器中包含攔截器,一個請求過來 ,先進行過濾器處理,看程序是否受理該請求 。 過濾器放過后 , 程序中的攔截器進行處理 。

1、攔截器不依賴servlet容器,過濾器依賴;

2、攔截器是基於java反射機制來實現的,過濾器基於回調

過濾器:關注web請求;

攔截器:關注方法調用;

Spring攔截器分類

spring中攔截器主要分兩種,一個是HandlerInterceptor,一個是MethodInterceptor。

HandlerInterceptor

HandlerInterceptor是springMVC項目中的攔截器,它攔截的目標是請求的地址,比MethodInterceptor先執行。

HandlerInterceptor攔截的是請求地址,所以針對請求地址做一些驗證、預處理等操作比較合適。當你需要統計請求的響應時間時MethodInterceptor將不太容易做到,因為它可能跨越很多方法或者只涉及到已經定義好的方法中一部分代碼。

實現一個HandlerInterceptor攔截器可以直接實現HandlerInterceptor接口,也可以繼承HandlerInterceptorAdapter類。

看下UML:

HandlerInterceptorAdapter.class
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {
    public HandlerInterceptorAdapter() {
    }
   //在業務處理器處理請求之前被調用
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }
  //在業務處理器處理請求完成之后,生成視圖之前執行  
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }
   // 在DispatcherServlet完全處理完請求之后被調用,可用於清理資源  
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }

    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    }
}

執行順序如圖:

具體體現在 DispatcherServlet.class  doDispatch()  方法中,看下源碼:

 protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            try {
                ModelAndView mv = null;
                Object dispatchException = null;

                try {
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }

                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }

                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }

                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }

                    this.applyDefaultViewName(processedRequest, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
                    dispatchException = var20;
                } catch (Throwable var21) {
                    dispatchException = new NestedServletException("Handler dispatch failed", var21);
                }

                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
            } catch (Throwable var23) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
            }

        } finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if (multipartRequestParsed) {
                this.cleanupMultipart(processedRequest);
            }

        }
    }

現在需要一個簡單的demo,深入了解幾個方法:

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class SecurityInterceptor extends HandlerInterceptorAdapter {

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        System.out.println("SecurityInterceptor  >>>>>>>>1");

        return true;
    }
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class WebSecurityConfig extends WebMvcConfigurationSupport {

    @Bean
    public SecurityInterceptor getSecurityInterceptor() {
        return new SecurityInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        InterceptorRegistration addInterceptor = registry.addInterceptor(getSecurityInterceptor());

        // 排除配置
        addInterceptor.excludePathPatterns("/403");
        addInterceptor.excludePathPatterns("/toLogin");
        addInterceptor.excludePathPatterns("/login**");

        // 攔截配置
        addInterceptor.addPathPatterns("/**");
    }
}

啟動工程(springboot工程):

 請求:http://localhost:8080/toLogin ,因為配置了排除設置,后台無打印。

請求:http://localhost:8080/userInfo/userAdd,后台有打印。

發散:如果是多個攔截器,他們preHandle、postHandle、afterCompletion方法執行順序是什么?

看下demo:

import org.springframework.lang.Nullable;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class SecurityInterceptor extends HandlerInterceptorAdapter {

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        System.out.println("SecurityInterceptor.preHandle  >>>>>>>>1");

        return true;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        System.out.println("SecurityInterceptor.postHandle  >>>>>>>>1");
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        System.out.println("SecurityInterceptor.afterCompletion  >>>>>>>>1");
    }
}
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloInterceptor extends HandlerInterceptorAdapter {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("HelloInterceptor.preHandle  >>>>>>>>3");
        return true;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        System.out.println("HelloInterceptor.postHandle  >>>>>>>>3");
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        System.out.println("HelloInterceptor.afterCompletion  >>>>>>>>3");
    }
}
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class RoleAuthorizationInterceptor extends HandlerInterceptorAdapter {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("RoleAuthorizationInterceptor.preHandle  >>>>>>>>2");
        return true;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        System.out.println("RoleAuthorizationInterceptor.postHandle  >>>>>>>>2");
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        System.out.println("RoleAuthorizationInterceptor.afterCompletion  >>>>>>>>2");
    }
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class WebSecurityConfig extends WebMvcConfigurationSupport {

    @Bean
    public SecurityInterceptor getSecurityInterceptor() {
        return new SecurityInterceptor();
    }

    @Bean
    public HelloInterceptor getHelloInterceptor() {
        return new HelloInterceptor();
    }

    @Bean
    public RoleAuthorizationInterceptor getRoleAuthorizationInterceptor() {
        return new RoleAuthorizationInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        InterceptorRegistration addInterceptor = registry.addInterceptor(getSecurityInterceptor());

        // 排除配置
        addInterceptor.excludePathPatterns("/403");
        addInterceptor.excludePathPatterns("/toLogin");
        addInterceptor.excludePathPatterns("/login**");

        // 攔截配置
        addInterceptor.addPathPatterns("/**");

        InterceptorRegistration roleInter = registry.addInterceptor(getRoleAuthorizationInterceptor());
        // 攔截配置
        roleInter.addPathPatterns("/**");

        InterceptorRegistration helloInter = registry.addInterceptor(getHelloInterceptor());
        helloInter.addPathPatterns("/**");

    }
}

執行結果:

如果攔截器的preHandle()返回false,結果會怎樣,改下demo:

WebSecurityConfig.java

 @Override
    public void addInterceptors(InterceptorRegistry registry) {
        InterceptorRegistration addInterceptor = registry.addInterceptor(getSecurityInterceptor());

        // 排除配置
        /*addInterceptor.excludePathPatterns("/403");
        addInterceptor.excludePathPatterns("/toLogin");
        addInterceptor.excludePathPatterns("/login**");*/

        // 攔截配置
        addInterceptor.addPathPatterns("/**");

        InterceptorRegistration roleInter = registry.addInterceptor(getRoleAuthorizationInterceptor());
        // 攔截配置
        roleInter.addPathPatterns("/**");

        InterceptorRegistration helloInter = registry.addInterceptor(getHelloInterceptor());
        helloInter.addPathPatterns("/**");

    }
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("RoleAuthorizationInterceptor.preHandle  >>>>>>>>2");
        return false;
    }

其他不變,運行結果:

通過源碼分析,當prehandle返回false,則執行triggerAfterCompletion()執行攔截器的afterCompletion()方法。

if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HandlerInterceptor[] interceptors = this.getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
                HandlerInterceptor interceptor = interceptors[i];
                if (!interceptor.preHandle(request, response, this.handler)) {
                    this.triggerAfterCompletion(request, response, (Exception)null);
                    return false;
                }
            }
        }

        return true;
    }

如果preHandle都返回true,postHandle()異常,又會是什么情況呢?

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        System.out.println("RoleAuthorizationInterceptor.postHandle  >>>>>>>>2");
        throw new NullPointerException();
    }

結果:

結論:

1、如果多個攔截器,執行順序:preHandle() :123 ,postHandle():321,afterCompletion():321

2、preHandle() 返回false,不會往下執行

3、preHandle()返回true的攔截器,必然會執行他的afterCompletion();

4、如果preHandle()都返回true,有一個攔截器的postHandle()拋出異常,則后面攔截器的postHandle()不會執行。(注意:寫代碼時要注意)

 

參考:

https://www.cnblogs.com/niceyoo/p/8735637.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM