사실 3.1 얘기를 인터셉터로 시작하려고 했던 것은 아니다. 지난 포스팅의 핵심은 자바콘픽의 사용방법이었고, @MVC 콘픽 클래스에서 인터셉터를 적용하는 메소드의 예를 든 것은 문제가 생겼을 때 난처한 결과를 맞을 수 있는 적절한 예이기 때문이다. 자세한 설명은 내년중에 마무리할 토비의 스프링 3 개정판에서 다루겠지만, 그래도 눈치를 채고 문제를 짚어낼 분이 있을까 싶어서 질문으로 마무리해본 것인데, 대부분 별 관심이 없는듯하고, 몇몇분은 그냥 답 내놓으라고만 하니…

유일하게 SuHong Lee님이 성의있는 의견을 주셨다.

혹시 인터셉터의 적용 순서를 알 수 없다는 것에대한 문제 인가요??
정확히는 모르겠네요
<mvc:>를 사용 하면 적용 순서를 알 수가 있을텐데
위와 같이 적용하면 순서가 어떻게 적용 될지 모를 수도 있을 듯하네요

스프링에는 Ordered 인터페이스를 구현하고 order프로퍼티를 노출시켜서 적용 순서를 지정할 수 있도록 만들어진 빈들이 제법 많다. 자주 눈에 띄는 것을 꼽자면 HandlerMapping류 빈들이 있다. 여러 핸들러매핑 전략을 동시에 적용할 때, 우선순위를 지정해서 가장 먼저 걸리는 핸들러를 적용하도록 만들 수 있다. 일부 뷰리졸버도 그렇고.

하지만 MVC 인터셉터의 API인 HandlerInterceptor나 그 구현 빈들은 Ordered가 적용되어있지 않다. 따라서 숫자값을 설정해서 그걸로 인터셉터의 적용 순서를 결정하지도 않는다.

인터셉터는 핸들러매핑 안에서 만들어지는 핸들러 호출용 HandlerExecutionChain안에 핸들러(컨트롤러라고도 부르는)와 함께 들어가서 실행체인의 일부로 만들어진다. 이렇게 만들어진 핸들러 체인은 DispatcherServlet에 의해서 적절한 순서에 의해서 인터셉터와 핸들러가 실행된다.

여러개의 인터셉터가 적용됐을 때, 각각이 독립적이고 서로 간섭이 없다면(핸들러체인 실행을 중단하는 따위) 실행 순서가 어떻게 되든 상관없다.  반면에 실행순서가 의미가 있는 경우라면 일정한 실행 순서가 보장이 되야 한다. HandlerInterceptor는 pre와 post가 반대의 반향으로 실행된다. 인터셉터 1,2,3이 있고, 1,2,3의 순서가 정해져있다면 1-2-3-handler-3-2-1-view-3-2-1의 순서로 실행될 것이다.

그럼 실행 순서는 어떻게 결정되는가?

일단 3.1얘기니까 3.1의 핵심인 WebMvcConfigurationSupport이나 WebMvcConfigurer를 사용했다고 보면, addInterceptors() 메소드를 구현 또는 오버라이딩하고, 파라미터로 전달된 InterceptorRegistry를 이용해서 인터셉터를 추가해주면 된다. 3.0에서 등장한 <mvc:interceptors>를 이용한 방법과 거의 동일하다.

InterceptorRegistry는 HandlerInterceptor 타입의 인터셉터와 WebRequestInterceptor 타입의 인터셉트 두 가지를 등록할 수 있게 되어있다. 일반적으로 HandlerInterceptor가 인터셉터를 만들 때 쓰는 대표적인 인터페이스지만, HandlerInterceptor는 Servlet API에 종속적이라는 단점이 있기 때문에, Portlet을 본격적으로 지원(원래 1.3에 들어가기로 한 기능인데, S1 2005인가 하면서 1.3을 건너뛰고 2.0으로 가기로 결정 했고, 그래서 2.0에 뒤늦게 등장했다)기 시작한 2.0부터는 웹 기술 API에 독립적인 WebRequestInterceptor가 등장해서 HandlerInterceptor와 함께 사용되기 시작했다. 서블릿 환경에서만 사용할 것이라면 HandlerInterceptor로 충분하겠지만, 서블릿, 포트릿 환경에 가릴 것 없이 사용될 수 있다면 WebRequestInterceptor가 적합하다. 그래서 지난번에 예로 들었던 OSIV인터셉터도 WebRequestInterceptor를 구현하고 있다.

이렇게 두가지 종류의 인터셉터가 섞여서 등록된다면 그 실행 순서는 어떻게 될까?

기본적으로는 인터셉터의 구현 방식은 순서에 영향을 주지 않는다. 실행순서는 레지스트리에 등록한 순서다. 내부에서 List로 저장해서 관리하기 때문에 순서가 보장된다. WebRequestInterceptor도 결국 실행 환경을 보고 적절한 아답터(WebRequestHandlerInterceptorAdapter 같은)를 통해서 HandlerInterceptor 타입으로 전환되서 실행체인으로 넘어가므로 사실 구분이 없다. 스프링(정확히는 Spring-mvc 모듈)은 내부적으로 이런 인터페이스들을 adapted interceptor라고 부른다.

그러면 그냥 인터셉터는 InterceptorRegistry에 add한 순서라고 보면 될까?

그런데, 그게 또 아니다.

인터셉터는 또 다시 단순 adapted interceptor와 mapped interceptor로 구분될 수 있다. 후자도 결국은 같은 HandlerInterceptor를 구현한 인터셉터지만 특정 URL패턴에 매칭되는 경우에만 실행되는 놈이다. <mvc:>를 썼다면 <mvc:mapping path="/secure/**"/>과 같이 사용했던 바로 그 방식이다.

그런데, 이렇게 매핑패턴을 가지는 mapped interceptor는 일반 인터셉터보다 실행 우선순위가 밀린다. 레지스트리 등록순서에 상관없이 나중에 실행된다.

정리하자면, 인터셉터는 단순 인터셉터(adapted interceptor)가 먼저 실행되고 매핑 인터셉터(mapped interceptor)가 그 다음에 실행되는데, 종류별로는 인터셉터 레지스트리에 등록된 순서대로 실행이 된다.  따라서 아무리 mapped interceptor를 먼저 등록해도 나중에 실행될 것으로 판단해야 한다.

만약 URL매핑을 하는 인터셉터가 우선적으로 실행되게 만들고 싶다면? 그때는 HandlerInterceptor를 구현해서, 거기서 URL비교를 해서 인터셉터 로직을 적용할지 말지를 결정하도록 만들고 URL패턴 없이 일반 인터셉터로 등록해서 사용하면 될 듯.

일단 여기까지.

Related posts:

  1. 유쾌한 이슈처리 재촉 메일

Facebook comments:

to “스프링 3.1 (2) HandlerInterceptor의 적용순서”

  1. just beneath, are many absolutely not associated internet sites to ours, having said that, they’re surely really worth going over

  2. Wonderful story, reckoned we could combine some unrelated information, nonetheless genuinely worth taking a appear, whoa did 1 discover about Mid East has got far more problerms also

Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

© 2017 Toby's Epril Suffusion theme by Sayontan Sinha