Heim  >  Artikel  >  Java  >  Analyse des SpringBoot-Interceptor-Quellcodes

Analyse des SpringBoot-Interceptor-Quellcodes

PHPz
PHPznach vorne
2023-05-15 12:28:231524Durchsuche

1. Was ist ein Interceptor (Interceptor) in Java? Er stellt einen Mechanismus bereit, der es Entwicklern ermöglicht, einen Code vor und nach der Ausführung einer Aktion auszuführen. Verhindert seine Ausführung vor der Ausführung und bietet außerdem eine Möglichkeit, wiederverwendbare Teile des Codes in der Aktion zu extrahieren. In AOP werden Interceptoren verwendet, um eine Methode oder ein Feld abzufangen, bevor darauf zugegriffen wird, und um dann bestimmte Operationen davor oder danach hinzuzufügen.

Die obige Aktion bezieht sich im Allgemeinen auf die Schnittstelle unserer Controller-Ebene.

2. Angepasster Interceptor

Im Allgemeinen ist das Anpassen eines Interceptors in drei Schritte unterteilt:

(1) Schreiben Sie einen Interceptor, um die HandlerInterceptor-Schnittstelle zu implementieren.

(2) Der Abfangjäger ist im Container registriert.

(3) Abfangregeln konfigurieren.

2.1 Einen Interceptor schreiben

Wir erstellen ein neues SpringBoot-Projekt und passen dann einen Interceptor LoginInterceptor an, um bestimmte Anfragen im nicht protokollierten Zustand abzufangen. Ab JDK 1.8 können Schnittstellenmethoden mit dem Standardschlüsselwort Standardimplementierungen haben. Um eine Schnittstelle zu implementieren, müssen Sie also nur die Methode ohne dieses Schlüsselwort implementieren.

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

/**
 * 登录拦截器
 */
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    /**
     * 目标方法执行之前执行
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 获取请求路径
        String requestUrl = request.getRequestURI();
        log.info("请求的路径是: {}", requestUrl);

        String username = request.getParameter("username");
        if (username != null) {
            // 放行
            return true;
        }

        request.setAttribute("msg", "请先登录");
        // 携带msg跳转到登录页
        request.getRequestDispatcher("/").forward(request, response);
        return false;
    }

    /**
     * 目标方法完成以后执行
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle执行");
    }

    /**
     * 页面渲染以后执行
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion执行");
    }
}

2.2 Interceptoren registrieren und konfigurieren

Wenn wir in SpringBoot die Konfiguration anpassen müssen, müssen wir nur die WebMvcConfigurer-Klasse implementieren und die entsprechende Methode überschreiben. Hier müssen wir den Interceptor konfigurieren, also schreiben Sie einfach seine addInterceptors-Methode neu.

import com.codeliu.interceptor.LoginInterceptor;
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 WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**")  // 拦截所有路径
                .excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**");  // 不拦截这些路径
    }
}

Beachten Sie, dass wir bei der Konfiguration zum Abfangen aller Pfade statische Ressourcen ausschließen müssen, da sonst die Bildstile abgefangen werden.

Durch die oben genannten Schritte haben wir einen dem System hinzugefügten Abfangjäger implementiert. Beginnen Sie einfach mit der Verifizierung.

3. Interceptor-Prinzip

Wir verwenden die Breakpoint-Debugging-Methode, um zu sehen, wie die Browseranforderung vom Anfang bis zum Backend verarbeitet wird. Fügen Sie einen Haltepunkt in die doDispatch-Methode von DispatcherServlet ein. Dies ist der Einstiegspunkt der Anfrage. Nachdem der Browser die Anfrage gesendet hat, wird sie von dieser Methode weitergeleitet und verarbeitet.

Analyse des SpringBoot-Interceptor-QuellcodesStarten Sie die Anwendung im Debug-Modus, greifen Sie auf eine beliebige Schnittstelle zu und verfolgen Sie den Codeprozess

3.1 Finden Sie den Handler, der die Anfrage verarbeiten kann, und alle Abfangjäger des Handlers

Analyse des SpringBoot-Interceptor-QuellcodesHier haben wir den HandlerExecutionChain und gefunden die Interceptor-Kette, die aus drei Interceptoren besteht: Interceptor, unserem benutzerdefinierten

und den standardmäßigen zwei Interceptoren des Systems.

LoginInterceptor3.2 Führen Sie die preHandle-Methode des Interceptors aus.

In der doDispatch-Methode gibt es die folgenden zwei Codezeilen.

// 执行拦截器的preHandle方法,如果返回为fasle,则直接return,不执行目标方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    return;
}

// 反射执行目标方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

Wir geben die applyPreHandle-Methode ein, um die Logik der Methode anzuzeigen Wenn der aktuelle Interceptor Wenn die preHandle-Methode true zurückgibt, wird die preHandle-Methode des nächsten Interceptors weiterhin ausgeführt, andernfalls wird die afterCompletion-Methode des Interceptors ausgeführt.

Dann schauen wir uns die Logik der Methode triggerAfterCompletion an.

/**
 * Apply preHandle methods of registered interceptors.
 * @return {@code true} if the execution chain should proceed with the
 * next interceptor or the handler itself. Else, DispatcherServlet assumes
 * that this interceptor has already dealt with the response itself.
 */
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 遍历拦截器
    for (int i = 0; i < this.interceptorList.size(); i++) {
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        // 执行当前拦截器的preHandle方法
        if (!interceptor.preHandle(request, response, this.handler)) {
            // 如果preHandle方法返回为false,则执行当前拦截器的afterCompletion方法
            triggerAfterCompletion(request, response, null);
            return false;
        }
        // 记录当前拦截器的下标
        this.interceptorIndex = i;
    }
    return true;
}

Durch den obigen Code wissen wir, dass die afterCompletion-Methode des Interceptors umgekehrt ausgeführt wird.

3.3 Führen Sie die Zielmethode aus

Wenn alle PreHandle-Methoden des oben genannten Interceptors true zurückgeben, gibt es in der doDispatch-Methode keine direkte Rückgabe, aber die Zielmethode wird weiterhin ausgeführt. Wenn die preHandle-Methode eines Interceptors false zurückgibt, kehrt die doDispatch-Methode nach der Ausführung der afterCompletion-Methode des Interceptors (des Interceptors, der die preHandle-Methode ausgeführt hat) direkt zurück und die Zielmethode wird nicht ausgeführt.

Führen Sie die Zielmethode über den folgenden Code aus

/**
 * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
 * Will just invoke afterCompletion for all interceptors whose preHandle invocation
 * has successfully completed and returned true.
 */
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
    // 反向遍历拦截器
    for (int i = this.interceptorIndex; i >= 0; i--) {
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        try {
            // 执行当前拦截器的afterCompletion方法
            interceptor.afterCompletion(request, response, this.handler, ex);
        }
        catch (Throwable ex2) {
            logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
        }
    }
}

Ich werde nicht auf die spezifische interne Ausführung achten, sondern auf die Logik nach der Ausführung.

3.4 Führen Sie die postHandle-Methode des Interceptors aus.

Nachdem die Zielmethode ausgeführt wurde, geht der Code aus.

// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
.

Sehen Sie sich die Logik von applyPostHandle an Methode des Abfangjägers

Weiter Gehen Sie nach unten

mappedHandler.applyPostHandle(processedRequest, response, mv);

und geben Sie diese Methode ein. Diese Methode verarbeitet die Ausführungsergebnisse und rendert die Seite. Führen Sie am Ende dieser Methode den folgenden Code aus

3.6 Ausnahmebehandlung

Wenn während der Ausführung der doDispatch-Methode eine Ausnahme ausgelöst wird, lösen Ausnahmen im Catch-Modul die Ausführung der afterCompletion-Methode aus

Analyse des SpringBoot-Interceptor-Quellcodes

Das obige ist der detaillierte Inhalt vonAnalyse des SpringBoot-Interceptor-Quellcodes. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen