search
HomeJavajavaTutorialSpringBoot interceptor source code analysis

SpringBoot interceptor source code analysis

May 15, 2023 pm 12:28 PM
springboot

1. What is an interceptor?

The interceptor (Interceptor) in Java is an object that dynamically intercepts Action calls. It provides a mechanism that allows developers to execute a piece of code before and after an Action is executed. , can also prevent the execution of an Action before it is executed, and also provides a way to extract reusable parts of the code in the Action. In AOP, interceptors are used to intercept a method or field before it is accessed, and then add certain operations before or after.

The Action above generally refers to the interface of our Controller layer.

2. Customized interceptor

Generally, customizing an interceptor is divided into three steps

(1) Write an interceptor to implement the HandlerInterceptor interface.

(2) The interceptor is registered in the container.

(3) Configure interception rules.

2.1 Writing an interceptor

We create a new SpringBoot project, and then customize an interceptor LoginInterceptor to intercept certain requests in the non-logged-in state. Starting from JDK 1.8, interface methods with the default keyword can have default implementations, so to implement an interface you only need to implement the method without this keyword.

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 Registering and configuring interceptors

In SpringBoot, when we need to customize the configuration, we only need to implement the WebMvcConfigurer class and rewrite the corresponding method. Here we need to configure the interceptor, so just rewrite its addInterceptors method.

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/**");  // 不拦截这些路径
    }
}

Note that if we configure to intercept all paths, we must exclude static resources, otherwise the image styles will be intercepted.

Through the above steps, we have implemented an interceptor added to the system. Just start verification.

3. Interceptor Principle

We use the breakpoint debugging method to see how the browser request is processed from the beginning to the backend. Set a breakpoint in the doDispatch method of DispatcherServlet. This is the entry point for the request. After the browser sends the request, this method forwards and processes it.

SpringBoot interceptor source code analysis

Start the application in debug mode, access any interface, and track the code flow

3.1 Find the handler that can handle the request and all the interceptors of the handler

SpringBoot interceptor source code analysis

Here we found the HandlerExecutionChain and the interceptor chain. There are three interceptors in it, our custom LoginInterceptor and the system's default two interceptors.

3.2 Execute the preHandle method of the interceptor

In the doDispatch method, there are the following two lines of code

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

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

We enter the applyPreHandle method to see the logic of the method

/**
 * 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;
}

Through the above code, we know that if the preHandle method of the current interceptor returns true, the preHandle method of the next interceptor will continue to be executed, otherwise the afterCompletion method of the interceptor will be executed.

Then let’s look at the logic of the triggerAfterCompletion method.

/**
 * 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);
        }
    }
}

Through the above code, we know that the afterCompletion method of the interceptor is executed in reverse.

3.3 Execute the target method

If all preHandle methods of the above interceptor return true, then there will not be a direct return in the doDispatch method, but the target method will continue to be executed. If the preHandle method of any interceptor returns false, then after executing the afterCompletion method of the interceptor (the interceptor that has executed the preHandle method), the doDispatch method will directly return and the target method will not be executed.

Execute the target method through the following code

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

I won’t look at the specific internal execution, but look at the logic after execution.

3.4 Execute the postHandle method of the interceptor

After the target method is executed, the code goes down

mappedHandler.applyPostHandle(processedRequest, response, mv);

View the logic of applyPostHandle

/**
 * Apply postHandle methods of registered interceptors.
 */
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
    throws Exception {
	// 反向遍历
    for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        // 执行当前拦截器的postHandle方法
        interceptor.postHandle(request, response, this.handler, mv);
    }
}

Execute the interception in reverse order The postHandle method of the interceptor

3.5 Execute the afterCompletion method of the interceptor

Continue going down

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

Enter this method, which will process the execution results and render the page. This method At the end, execute the following code

SpringBoot interceptor source code analysis

3.6 Exception handling

If an exception is thrown during the execution of the doDispatch method, it will be triggered in the catch module Execute afterCompletion method

SpringBoot interceptor source code analysis

The above is the detailed content of SpringBoot interceptor source code analysis. For more information, please follow other related articles on the PHP Chinese website!

Statement
This article is reproduced at:亿速云. If there is any infringement, please contact admin@php.cn delete
How do I use Maven or Gradle for advanced Java project management, build automation, and dependency resolution?How do I use Maven or Gradle for advanced Java project management, build automation, and dependency resolution?Mar 17, 2025 pm 05:46 PM

The article discusses using Maven and Gradle for Java project management, build automation, and dependency resolution, comparing their approaches and optimization strategies.

How do I create and use custom Java libraries (JAR files) with proper versioning and dependency management?How do I create and use custom Java libraries (JAR files) with proper versioning and dependency management?Mar 17, 2025 pm 05:45 PM

The article discusses creating and using custom Java libraries (JAR files) with proper versioning and dependency management, using tools like Maven and Gradle.

How do I implement multi-level caching in Java applications using libraries like Caffeine or Guava Cache?How do I implement multi-level caching in Java applications using libraries like Caffeine or Guava Cache?Mar 17, 2025 pm 05:44 PM

The article discusses implementing multi-level caching in Java using Caffeine and Guava Cache to enhance application performance. It covers setup, integration, and performance benefits, along with configuration and eviction policy management best pra

How can I use JPA (Java Persistence API) for object-relational mapping with advanced features like caching and lazy loading?How can I use JPA (Java Persistence API) for object-relational mapping with advanced features like caching and lazy loading?Mar 17, 2025 pm 05:43 PM

The article discusses using JPA for object-relational mapping with advanced features like caching and lazy loading. It covers setup, entity mapping, and best practices for optimizing performance while highlighting potential pitfalls.[159 characters]

How does Java's classloading mechanism work, including different classloaders and their delegation models?How does Java's classloading mechanism work, including different classloaders and their delegation models?Mar 17, 2025 pm 05:35 PM

Java's classloading involves loading, linking, and initializing classes using a hierarchical system with Bootstrap, Extension, and Application classloaders. The parent delegation model ensures core classes are loaded first, affecting custom class loa

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
1 months agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Chat Commands and How to Use Them
1 months agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Atom editor mac version download

Atom editor mac version download

The most popular open source editor

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

EditPlus Chinese cracked version

EditPlus Chinese cracked version

Small size, syntax highlighting, does not support code prompt function

Dreamweaver Mac version

Dreamweaver Mac version

Visual web development tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor