本文章针对mvc:interceptors标签进行介绍,它的注册过程以及在访问时的拦截过程。
首先说下接口HandlerInterceptor,它有如下三个方法:
正常情况下,对于preHandle就是在在处理函数之前先执行,然后再执行处理函数,接着执行postHandle,最后再执行afterCompletion。afterCompletion无论是否出错是肯定要执行的,而postHandle则不是,不一定会执行。之后看源代码就知道他们的执行情况。
AsyncHandlerInterceptor接口则增添了afterConcurrentHandlingStarted方法,对于此还未研究,先不讨论。
HandlerInterceptorAdapter则默认实现了上述的接口,所以当我们仅仅要实现某个方法时,只需继承HandlerInterceptorAdapter,然后覆盖相应的方法。
然后我们就写一个类继承HandlerInterceptorAdapter来进行实验:LoginInterceptor如下:
没有做具体的内容,仅仅是打印出一些信息,方便查看执行顺序。
该接口的基本内容说完了,然后就看下它的配置说明:
其实在mvc:interceptors标签中,有两种类型的配置,一种直接配置一个bean(bean和ref归为一类),另一种还要配置上拦截的路径和排除的路径。直接配置的bean那就代表对所有的请求进行拦截,而对于mvc:interceptor则代表有着更精细的控制。
而mvc:interceptors的属性path-matcher则表示配置一个自定义的PathMatcher,它主要用来处理路径的匹配规则,默认采用的PathMatcher为AntPathMatcher,具有ant风格的路径规则,如?表示任何单字符,*表示0个或多个字符,**表示0个或多个目录。
对于本工程来说具体的配置如下:
然后就进行源代码分析:
如何来处理xml文件中所配置的这些HandlerInterceptor的呢?
对于mvc:interceptors的解析同样需要我们去看BeanDefinitionParser的实现类,最终会找到InterceptorsBeanDefinitionParser:
这里就引出来MappedInterceptor的结构类型:
到这里就很明白了,虽然在mvc:interceptors标签中,配置interceptor形式不一样,但是最终都将以MappedInterceptor形式存储,同时来看下MappedInterceptor的match的方法:
这里便是PathMatcher对于excludePatterns、includePatterns 的使用规则,同时表明本身的PathMatcher若为空,则使用外部传来的PathMatcher。
至此解析mvc:interceptors标签的过程就完成了。它们最终会注册到ApplicationContext的上下文环境中,等待被使用。
谁会是他们的使用者呢?我们慢慢来看:
对于每一个请求,HandlerMapping都会找到对应的handler,并最终封装成一个HandlerExecutionChain,这个HandlerExecutionChain包含有handler和它对应的interceptors,HandlerExecutionChain如下:
既然是由HandlerMapping来产生的HandlerExecutionChain,则它需要为每一个它所管辖的handler来装配HandlerInterceptor。所以HandlerMapping必然是mvc:interceptors标签内容的使用者。
使用者:AbstractHandlerMapping,它的属性有:
这里便可以看到,它所使用的默认的PathMatcher为AntPathMatcher。接下来我们看下AbstractHandlerMapping的初始化方法:
detectMappedInterceptors探测ApplicationContext中已经解析过的MappedInterceptor,如下:
全部存放到AbstractHandlerMapping的mappedInterceptors属性上。
然后我们继续看看在请求到来时的具体拦截过程:
对于每个请求先找到对应的HandlerMapping,然后由这个handlerMapping来找到对应请求的handler,然后由handlerMapping自身的interceptor和这个handler来构建一个HandlerExecutionChain。代码如下:
这里便是找到一个合适的HandlerMapping,继续看下hm.getHandler(request)这个方法。
这里便是找到对应请求的handler。getHandlerExecutionChain(handler, request)这里便是构建HandlerExecutionChain的地方:
对于我们关注的重点为它会遍历AbstarctHandlerMapping的mappedInterceptors属性,然后使用默认的pathMatcher,即AntPathMatcher来判断当前的请求是否符合拦截条件,若符合则将mappedInterceptor放进HandlerExecutionChain 中。
至此一个HandlerExecutionChain便构建好了,包含一个handler和这个handler对应的interceptor。然后看下interceptor的执行过程:
先看重点1:
执行preHandle方法,一旦有一个preHandle返回false,则触发triggerAfterCompletion:
看下这里的for循环的条件,从interceptorIndex开始到0,逆序执行interceptor.afterCompletion。
重点2 postHandle:
这个没有什么特殊,preHandle只有参数HttpServletRequest和HttpServletResponse,而postHandle则加入了返回结果ModelAndView,我们可以对ModelAndView进行进一步的修改,此时的view(若有)还没有经过渲染。
重点3 :
这里可以看到,如果有view,则渲染完成之后,才会执行triggerAfterCompletion,同时不再拥有对ModelAndView的处理(已经完成了渲染)。所以我们就可以看到当有view时,afterCompletion和postHandle的明显区别。
重点4:当执行过程发生异常时,也会执行interceptor的afterCompletion方法。
这里要做下说明,对于preHandler方法是获取不到处理函数的参数值的,如果想对处理函数的参数值进行拦截处理,则要使用Spring AOP。
首先说下接口HandlerInterceptor,它有如下三个方法:
1
2
3
4
5
6
7
8
9
10
|
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;
void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;
|
正常情况下,对于preHandle就是在在处理函数之前先执行,然后再执行处理函数,接着执行postHandle,最后再执行afterCompletion。afterCompletion无论是否出错是肯定要执行的,而postHandle则不是,不一定会执行。之后看源代码就知道他们的执行情况。
AsyncHandlerInterceptor接口则增添了afterConcurrentHandlingStarted方法,对于此还未研究,先不讨论。
HandlerInterceptorAdapter则默认实现了上述的接口,所以当我们仅仅要实现某个方法时,只需继承HandlerInterceptorAdapter,然后覆盖相应的方法。
然后我们就写一个类继承HandlerInterceptorAdapter来进行实验:LoginInterceptor如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
@Override public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println( "preHandle" );
return super .preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println( "postHandle" );
super .postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println( "afterCompletion" );
super .afterCompletion(request, response, handler, ex);
}
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println( "afterConcurrentHandlingStarted" );
super .afterConcurrentHandlingStarted(request, response, handler);
}
|
没有做具体的内容,仅仅是打印出一些信息,方便查看执行顺序。
该接口的基本内容说完了,然后就看下它的配置说明:
1
2
3
4
5
6
7
8
|
<mvc:interceptors path-matcher= "xxx" >
<mvc:interceptor>
<mvc:mapping path= "xxx" />
<mvc:exclude-mapping path= "xxxx" />
<bean class = "xxxx" ></bean>
</mvc:interceptor>
<bean class = "com.lg.mvc.interceptor.LoginInterceptor" />
</mvc:interceptors>
|
其实在mvc:interceptors标签中,有两种类型的配置,一种直接配置一个bean(bean和ref归为一类),另一种还要配置上拦截的路径和排除的路径。直接配置的bean那就代表对所有的请求进行拦截,而对于mvc:interceptor则代表有着更精细的控制。
而mvc:interceptors的属性path-matcher则表示配置一个自定义的PathMatcher,它主要用来处理路径的匹配规则,默认采用的PathMatcher为AntPathMatcher,具有ant风格的路径规则,如?表示任何单字符,*表示0个或多个字符,**表示0个或多个目录。
对于本工程来说具体的配置如下:
1
2
3
|
<mvc:interceptors> <bean class = "com.lg.mvc.interceptor.LoginInterceptor" />
</mvc:interceptors>
|
然后就进行源代码分析:
如何来处理xml文件中所配置的这些HandlerInterceptor的呢?
对于mvc:interceptors的解析同样需要我们去看BeanDefinitionParser的实现类,最终会找到InterceptorsBeanDefinitionParser:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compDefinition);
//判断是否自定义了PathMatcher RuntimeBeanReference pathMatcherRef = null ;
if (element.hasAttribute( "path-matcher" )) {
pathMatcherRef = new RuntimeBeanReference(element.getAttribute( "path-matcher" ));
}
//获取所有的interceptor,在这里我们可以看到所有的interceptor最终都会构建成一个 //MappedInterceptor List<Element> interceptors = DomUtils.getChildElementsByTagName(element, "bean" , "ref" , "interceptor" );
for (Element interceptor : interceptors) {
RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor. class );
mappedInterceptorDef.setSource(parserContext.extractSource(interceptor));
mappedInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
ManagedList<String> includePatterns = null ;
ManagedList<String> excludePatterns = null ;
Object interceptorBean;
if ( "interceptor" .equals(interceptor.getLocalName())) {
includePatterns = getIncludePatterns(interceptor, "mapping" );
excludePatterns = getIncludePatterns(interceptor, "exclude-mapping" );
Element beanElem = DomUtils.getChildElementsByTagName(interceptor, "bean" , "ref" ).get( 0 );
interceptorBean = parserContext.getDelegate().parsePropertySubElement(beanElem, null );
}
else {
interceptorBean = parserContext.getDelegate().parsePropertySubElement(interceptor, null );
}
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue( 0 , includePatterns);
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue( 1 , excludePatterns);
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue( 2 , interceptorBean);
if (pathMatcherRef != null ) {
mappedInterceptorDef.getPropertyValues().add( "pathMatcher" , pathMatcherRef);
}
String beanName = parserContext.getReaderContext().registerWithGeneratedName(mappedInterceptorDef);
parserContext.registerComponent( new BeanComponentDefinition(mappedInterceptorDef, beanName));
}
parserContext.popAndRegisterContainingComponent();
return null ;
}
|
这里就引出来MappedInterceptor的结构类型:
1
2
3
4
5
6
7
|
private final String[] includePatterns;
private final String[] excludePatterns;
private final HandlerInterceptor interceptor;
private PathMatcher pathMatcher;
|
到这里就很明白了,虽然在mvc:interceptors标签中,配置interceptor形式不一样,但是最终都将以MappedInterceptor形式存储,同时来看下MappedInterceptor的match的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public boolean matches(String lookupPath, PathMatcher pathMatcher) {
PathMatcher pathMatcherToUse = ( this .pathMatcher != null ) ? this .pathMatcher : pathMatcher;
if ( this .excludePatterns != null ) {
for (String pattern : this .excludePatterns) {
if (pathMatcherToUse.match(pattern, lookupPath)) {
return false ;
}
}
}
if ( this .includePatterns == null ) {
return true ;
}
else {
for (String pattern : this .includePatterns) {
if (pathMatcherToUse.match(pattern, lookupPath)) {
return true ;
}
}
return false ;
}
}
|
这里便是PathMatcher对于excludePatterns、includePatterns 的使用规则,同时表明本身的PathMatcher若为空,则使用外部传来的PathMatcher。
至此解析mvc:interceptors标签的过程就完成了。它们最终会注册到ApplicationContext的上下文环境中,等待被使用。
谁会是他们的使用者呢?我们慢慢来看:
对于每一个请求,HandlerMapping都会找到对应的handler,并最终封装成一个HandlerExecutionChain,这个HandlerExecutionChain包含有handler和它对应的interceptors,HandlerExecutionChain如下:
1
2
3
4
5
6
7
|
private final Object handler;
private HandlerInterceptor[] interceptors;
private List<HandlerInterceptor> interceptorList;
private int interceptorIndex = - 1 ;
|
既然是由HandlerMapping来产生的HandlerExecutionChain,则它需要为每一个它所管辖的handler来装配HandlerInterceptor。所以HandlerMapping必然是mvc:interceptors标签内容的使用者。
使用者:AbstractHandlerMapping,它的属性有:
1
2
3
4
5
6
7
|
private PathMatcher pathMatcher = new AntPathMatcher();
private final List<Object> interceptors = new ArrayList<Object>();
private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<HandlerInterceptor>();
private final List<MappedInterceptor> mappedInterceptors = new ArrayList<MappedInterceptor>();
|
这里便可以看到,它所使用的默认的PathMatcher为AntPathMatcher。接下来我们看下AbstractHandlerMapping的初始化方法:
1
2
3
4
5
|
protected void initApplicationContext() throws BeansException {
extendInterceptors( this .interceptors);
detectMappedInterceptors( this .mappedInterceptors);
initInterceptors();
}
|
detectMappedInterceptors探测ApplicationContext中已经解析过的MappedInterceptor,如下:
1
2
3
4
5
|
protected void detectMappedInterceptors(List<MappedInterceptor> mappedInterceptors) {
mappedInterceptors.addAll(
BeanFactoryUtils.beansOfTypeIncludingAncestors(
getApplicationContext(), MappedInterceptor. class , true , false ).values());
}
|
全部存放到AbstractHandlerMapping的mappedInterceptors属性上。
然后我们继续看看在请求到来时的具体拦截过程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null ;
boolean multipartRequestParsed = false ;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null ;
Exception dispatchException = null ;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
//略 } |
对于每个请求先找到对应的HandlerMapping,然后由这个handlerMapping来找到对应请求的handler,然后由handlerMapping自身的interceptor和这个handler来构建一个HandlerExecutionChain。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this .handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'" );
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null ) {
return handler;
}
}
return null ;
}
|
这里便是找到一个合适的HandlerMapping,继续看下hm.getHandler(request)这个方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
if (handler == null ) {
handler = getDefaultHandler();
}
if (handler == null ) {
return null ;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
return getHandlerExecutionChain(handler, request);
}
|
这里便是找到对应请求的handler。getHandlerExecutionChain(handler, request)这里便是构建HandlerExecutionChain的地方:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
chain.addInterceptors(getAdaptedInterceptors());
String lookupPath = this .urlPathHelper.getLookupPathForRequest(request);
for (MappedInterceptor mappedInterceptor : this .mappedInterceptors) {
if (mappedInterceptor.matches(lookupPath, this .pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
return chain;
}
|
对于我们关注的重点为它会遍历AbstarctHandlerMapping的mappedInterceptors属性,然后使用默认的pathMatcher,即AntPathMatcher来判断当前的请求是否符合拦截条件,若符合则将mappedInterceptor放进HandlerExecutionChain 中。
至此一个HandlerExecutionChain便构建好了,包含一个handler和这个handler对应的interceptor。然后看下interceptor的执行过程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null ;
boolean multipartRequestParsed = false ;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null ;
Exception dispatchException = null ;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null ) {
noHandlerFound(processedRequest, response);
return ;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET" .equals(method);
if (isGet || "HEAD" .equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug( "Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if ( new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return ;
}
}
//重点1 这里执行interceptor的preHandle方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return ;
}
//这里执行处理函数 try {
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return ;
}
}
applyDefaultViewName(request, mv);
//重点2:这里执行interceptor的postHandle方法 mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
//重点3:这里执行interceptor的afterCompletion方法 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
//重点4:当出现异常时,仍然执行afterCompletion方法 catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return ;
}
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
|
先看重点1:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (getInterceptors() != null ) {
for ( int i = 0 ; i < getInterceptors().length; i++) {
HandlerInterceptor interceptor = getInterceptors()[i];
if (!interceptor.preHandle(request, response, this .handler)) {
triggerAfterCompletion(request, response, null );
return false ;
}
this .interceptorIndex = i;
}
}
return true ;
}
|
执行preHandle方法,一旦有一个preHandle返回false,则触发triggerAfterCompletion:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {
if (getInterceptors() == null ) {
return ;
}
for ( int i = this .interceptorIndex; i >= 0 ; i--) {
HandlerInterceptor interceptor = getInterceptors()[i];
try {
interceptor.afterCompletion(request, response, this .handler, ex);
}
catch (Throwable ex2) {
logger.error( "HandlerInterceptor.afterCompletion threw exception" , ex2);
}
}
}
|
看下这里的for循环的条件,从interceptorIndex开始到0,逆序执行interceptor.afterCompletion。
重点2 postHandle:
1
2
3
4
5
6
7
8
9
|
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
if (getInterceptors() == null ) {
return ;
}
for ( int i = getInterceptors().length - 1 ; i >= 0 ; i--) {
HandlerInterceptor interceptor = getInterceptors()[i];
interceptor.postHandle(request, response, this .handler, mv);
}
}
|
这个没有什么特殊,preHandle只有参数HttpServletRequest和HttpServletResponse,而postHandle则加入了返回结果ModelAndView,我们可以对ModelAndView进行进一步的修改,此时的view(若有)还没有经过渲染。
重点3 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false ;
if (exception != null ) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug( "ModelAndViewDefiningException encountered" , exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null );
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null );
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug( "Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling" );
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return ;
}
if (mappedHandler != null ) {
mappedHandler.triggerAfterCompletion(request, response, null );
}
}
|
这里可以看到,如果有view,则渲染完成之后,才会执行triggerAfterCompletion,同时不再拥有对ModelAndView的处理(已经完成了渲染)。所以我们就可以看到当有view时,afterCompletion和postHandle的明显区别。
重点4:当执行过程发生异常时,也会执行interceptor的afterCompletion方法。
这里要做下说明,对于preHandler方法是获取不到处理函数的参数值的,如果想对处理函数的参数值进行拦截处理,则要使用Spring AOP。