SpringBoot 차단기 및 소스 코드 상세 분석

1.차단기 가 무엇 입 니까
자바 의 차단기(Interceptor)는 동적 차단 Action 호출 대상 으로 개발 자 들 이 Action 이 실 행 된 전후 에 코드 를 실행 할 수 있 는 메커니즘 을 제공 하고 Action 이 실 행 될 때 까지 실행 을 막 을 수 있 으 며 Action 에서 일부 코드 를 다시 사용 할 수 있 는 방식 도 제공 합 니 다.AOP 에서 차단 기 는 어떤 방법 이나 필드 가 접근 하기 전에 차단 한 다음 에 이전 또는 그 후에 어떤 조작 을 추가 하 는 데 사 용 됩 니 다.
위의 Action 은 일반적으로 우리 Controller 층 의 인 터 페 이 스 를 가리킨다.
2.사용자 정의 차단기
일반적으로 사용자 정의 차단 기 는 세 단계 로 나 뉜 다.
(1)Handler Interceptor 인 터 페 이 스 를 실현 하 는 차단 기 를 작성 합 니 다.
(2)차단 기 를 용기 에 등록 합 니 다.
(3)차단 규칙 을 설정 합 니 다.
2.1 작성 차단기
SpringBoot 프로젝트 를 새로 만 든 다음 로그 인 되 지 않 은 상태 에서 요청 을 차단 하 는 차단기 LoginInterceptor 를 사용자 정의 합 니 다.JDK 1.8 부터 인터페이스의 방법 에 default 키 워드 를 더 하면 기본적으로 실 현 될 수 있 기 때문에 하나의 인 터 페 이 스 를 실현 하려 면 이 키 워드 를 추가 하지 않 은 방법 만 실현 해 야 한다.

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 차단기 등록 및 설정
SpringBoot 에서 사용자 정의 설정 이 필요 할 때 WebMvcConfigure 류 에 대응 하 는 방법 만 다시 쓰 면 됩 니 다.차단 기 를 설정 해 야 합 니 다.addInterceptors 방법 을 다시 쓰 면 됩 니 다.

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/**");  //        
    }
}
모든 경 로 를 차단 할 경 로 를 설정 하면 정적 자원 을 제거 해 야 합 니 다.그렇지 않 으 면 그림 스타일 이 차단 되 어 있 습 니 다.
위의 몇 단 계 를 통 해 우 리 는 시스템 에 차단 기 를 추가 하 는 것 을 실현 했다.인증 을 시작 하면 됩 니 다.
3.차단기 원리
브 라 우 저 요청 부터 백 엔 드 까지 디 버 깅 을 중단 하 는 방법 을 보 겠 습 니 다.Dispatcher Servlet 의 doDispatch 방법 에 정지점 을 찍 습 니 다.이것 은 요청 의 입구 입 니 다.브 라 우 저 에서 요청 을 보 낸 후 이 방법 으로 퍼 가기 와 처 리 를 합 니 다.

debug 모드 시작 응용,임의의 인터페이스 접근,추적 코드 프로 세 스
3.1 요청 을 처리 할 수 있 는 handler 와 handler 의 모든 차단 기 를 찾 습 니 다.

Handler ExecutionChain 과 차단기 체인 을 찾 았 습 니 다.그 안에 세 개의 차단기 가 있 습 니 다.사용자 정의LoginInterceptor와 시스템 기본 두 개의 차단기 가 있 습 니 다.
3.2 차단 기 를 실행 하 는 preHandle 방법
doDispatch 방법 에는 다음 두 줄 의 코드 가 있 습 니 다.

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

//         
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
우 리 는 애플 리 케 이 션 PreHandle 방법 에 들 어가 이 방법의 논 리 를 살 펴 보 자.

/**
 * 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;
}
위의 코드 를 통 해 현재 차단기 의 preHandle 방법 이 true 로 되 돌아 오 면 다음 차단기 의 preHandle 방법 을 계속 실행 할 것 임 을 알 고 있 습 니 다.그렇지 않 으 면 차단기 의 after Complete 방법 을 실행 할 것 입 니 다.
그럼 trigger AfterComplete 방법의 논 리 를 봅 시다.

/**
 * 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);
        }
    }
}
위의 코드 를 통 해 우 리 는 차단기 의 after Completion 방법 이 역방향 으로 실행 되 었 다 는 것 을 알 고 있다.
3.3 목표 수행 방법
위의 차단기 의 모든 preHandle 방법 이 true 로 되 돌아 오 면 doDispatch 방법 에서 직접 return 하지 않 고 목표 방법 을 계속 수행 합 니 다.차단기 의 preHandle 방법 이 false 로 되 돌아 오 면 차단기(preHandle 방법 이 실 행 된 차단기)의 after Complete 방법 을 실행 한 후 doDispatch 방법 에서 직접 return 하여 목표 방법 을 실행 하지 않 습 니 다.
아래 코드 를 통 해 목표 방법 을 실행 합 니 다.

// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
내부 에서 구체 적 으로 어떻게 집행 하 는 지 는 보지 않 고 집행 후의 논 리 를 살 펴 보 자.
3.4 차단 기 를 실행 하 는 post Handle 방법
목표 방법 이 실 행 된 후 코드 를 내 려 갑 니 다.

mappedHandler.applyPostHandle(processedRequest, response, mv);
apply Post Handle 의 논리 보기

/**
 * 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);
    }
}
차단 기 를 거꾸로 실행 하 는 post Handle 방법
3.5 차단기 의 after Completion 방법 을 실행 합 니 다.
계속 내 려 가세 요.

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
이 방법 에 들 어가 면 이 방법 은 실행 결 과 를 처리 하고 페이지 를 렌 더 링 합 니 다.이 방법 은 마지막 으로 아래 코드 를 실행 합 니 다.

3.6 이상 처리
doDispatch 방법 을 실행 하 는 과정 에서 이상 을 던 지면 catch 모듈 에서 after Completion 방법 을 실행 합 니 다.

4.총화
위의 과정 은 대략 다음 과 같은 몇 단계 로 요약 할 수 있다.
(1)현재 요청 에 따라 요청 을 처리 할 수 있 는 handler 와 handler 의 모든 차단 기 를 찾 습 니 다.
(2)모든 차단기 의 preHandle 방법 을 순서대로 실행 합 니 다.
현재 차단기 의 preHandle 방법 이 true 로 되 돌아 오 면 다음 차단기 의 preHandle 방법 을 실행 합 니 다.현재 차단기 가 false 로 되 돌아 가면 실 행 된 모든 차단기 의 after Complete 를 거꾸로 실행 합 니 다.
(3)어떤 차단기 가 false 로 돌아 가면 되 돌아 가 고 목표 방법 을 실행 하지 않 습 니 다.
(4)모든 차단 기 는 true 로 돌아 가 목표 방법 을 실행 합 니 다.
(5)모든 차단기 의 post Handle 방법 을 거꾸로 실행 합 니 다.
(6)앞의 절차 에 이상 이 있 으 면 거꾸로 after Complete 방법 을 실행 합 니 다.
(7)페이지 가 렌 더 링 에 성공 하면 after Complete 방법 을 거꾸로 실행 합 니 다.

스프링 부 트 차단기 와 소스 코드 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.스프링 부 트 차단기 에 관 한 더 많은 내용 은 예전 의 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 도 많은 응원 부 탁 드 리 겠 습 니 다!

좋은 웹페이지 즐겨찾기