在线咨询

深入剖析Spring Web源码(十六) - 处理器映射,处理器适配器以及处理器的实现 - 拦截器的实现架构


4.2.2.4 拦截器的实现架构

从前面的章节分析中得知,处理器映射机制支持处理器拦截器功能。处理器拦截器应用一定的功能在满足一定条件的请求上。

处理器拦截器必须实现HandlerInterceptor接口,它定义了三个方法如下,

preHandle()

任何处理器调用之前调用的方法。它返回一个布尔值,如果返回真,则继续调用处理器链的其他处理器或者拦截器,如果返回假,则停止调用处理器链的其他处理器或者拦截器,在这种情况下,它假设拦截器已经处理了HTTP请求,而且写入了HTTP响应。

postHandle()

任何处理器调用之后调用的方法。

afterCompletion()

整个请求处理之后调用的方法。

如下代码注释,

public   interface  HandlerInterceptor {

 

     //  处理器执行之前调用的方法,可以用来对处理器进行预处理,如果返回布尔值假,则终止处理请求

     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;

 

}

在对流程进行分析的时候,我们看到有两个层次的处理器拦截器的实现。在抽象的处理器映射的层次上可以配置处理器拦截器。这些拦截器会应用到所有的处理器上。然后,在抽象URL处理器映射的层次上可以根据URL Pattern配置处理器拦截器,这些拦截器只应用到匹配URL Pattern的处理器上。如下图所示,

 

 

图表 4‑37

在抽象处理器映射类中,它声明了一个处理器拦截器的数组,但是并没有提供这个数组的存取方法。这个处理器映射是通过另外一个数组属性适配得到的。如下代码所示,

public   abstract   class  AbstractHandlerMapping  extends  WebApplicationObjectSupport

         implements  HandlerMapping, Ordered {

     //  通用类型的拦截器对象

     //  包含处理器拦截器,它用标准 Servlet HTTP 请求对象和标准 Servlet HTTP 响应对象作为方法参数

     //  也包含 Web Request 拦截器,   它使用 Spring 对请求和响应的封装类型,  WebRequest WebResponse

     private   final  List<Object> interceptors =  new  ArrayList<Object>();

 

     //  适配后的处理器适配器

     private  HandlerInterceptor[] adaptedInterceptors;

 

     //  提供方法设置 HandlerInterceptor WebRequestInterceptor

     public   void  setInterceptors(Object[] interceptors) {

         this .interceptors.addAll(Arrays.asList(interceptors));

    }

   

     //  当应用程序环境初始化的时候,初始化拦截器

     protected   void  initApplicationContext()  throws  BeansException {

        extendInterceptors( this .interceptors);

        initInterceptors();

    }

   

     //  子类可以改写添加新的拦截器

     protected   void  extendInterceptors(List<Object> interceptors) {

    }

 

 

     protected   void  initInterceptors() {

         if  (! this .interceptors.isEmpty()) {

             this .adaptedInterceptors =  new  HandlerInterceptor[ this .interceptors.size()];

             //  对于每个对象类型的拦截器适配到标准的处理器拦截器

             for  ( int  i = 0; i <  this .interceptors.size(); i++) {

                Object interceptor =  this .interceptors.get(i);

                 if  (interceptor ==  null ) {

                     throw   new  IllegalArgumentException("Entry number " + i + " in interceptors array is null");

                }

                 this .adaptedInterceptors[i] = adaptInterceptor(interceptor);

            }

        }

    }

   

     protected  HandlerInterceptor adaptInterceptor(Object interceptor) {

         //  如果已经是处理器拦截器类型,不需要适配

         if  (interceptor  instanceof  HandlerInterceptor) {

             return  (HandlerInterceptor) interceptor;

        }

         //  如果是 Web 请求拦截器,需要使用 WebRequestHandlerInterceptorAdapter 进行适配

         else   if  (interceptor  instanceof  WebRequestInterceptor) {

             return   new  WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);

        }

         //  不支持其他类型的拦截器

         else  {

             throw   new  IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName());

        }

    }

 

}

我们可以看到,它支持两种类型的拦截器,处理器拦截器和Web请求拦截器。处理器拦截器使用标准的HTTP请求和HTTP响应作为参数,而Web请求拦截器使用了Spring封装类型WebRequest和WebResponse。这是因为除了Servlet规范中的请求和响应以外,它还要支持Portlet中的请求和响应。如下Web请求拦截器代码注释,

public   interface  WebRequestInterceptor {

 

     //  处理器执行前调用,不支持在拦截器中结束处理器链的操作

     void  preHandle(WebRequest request)  throws  Exception;

 

     //  处理器执行后调用

     void  postHandle(WebRequest request, ModelMap model)  throws  Exception;

 

     //  请求处理完成后调用

     void  afterCompletion(WebRequest request, Exception ex)  throws  Exception;

 

}

有的时候,我们并不希望实现所有的三个方法,而是希望实现其中某一个,或者某些方法,Spring框架提供了处理器拦截器的适配器类来达到这样的目的。如下类图所示,

 

 

图表 4‑38

上图中,处理器拦截器适配器实现了处理器拦截器接口,子类只需要继承自处理器拦截器适配器并且根据业务逻辑需要改写其中的某些方法即可。

Web请求处理器拦截器适配器用来将一个Web请求拦截器适配成为一个标准的处理器拦截器。它应用在抽象处理器拦截器的内部实现上。

下面我们分析抽象URL处理器映射层次的处理器拦截器。这个层次的拦截器根据配置的URL Pattern应用到一部分的处理器上。如下代码所示,

public   abstract   class  AbstractUrlHandlerMapping  extends  AbstractHandlerMapping {

   

     //  映射拦截器集合,映射拦截器保存从 URL Pattern 到处理器拦截器的映射信息

     private  MappedInterceptors mappedInterceptors;

   

     //  可以在外部进行配置映射的拦截器

     public   void  setMappedInterceptors(MappedInterceptor[] mappedInterceptors) {

         this .mappedInterceptors =  new  MappedInterceptors(mappedInterceptors);

    }

 

   

    @Override

     //  Web 应用程序环境中查找映射的拦截器

     protected   void  initInterceptors() {

         super .initInterceptors();

       

         //  查找 Web 应用程序环境中所有的映射的拦截器

        Map<String, MappedInterceptor> mappedInterceptors = BeanFactoryUtils.beansOfTypeIncludingAncestors(

                getApplicationContext(), MappedInterceptor. class true false );

         if  (!mappedInterceptors.isEmpty()) {

             this .mappedInterceptors =  new  MappedInterceptors(mappedInterceptors.values().toArray(

                     new  MappedInterceptor[mappedInterceptors.size()]));

        }

 

    }

}

映射的拦截器是一个保存从URL Pattern到处理器拦截器的映射信息。如下代码所示,

public   final   class  MappedInterceptor {

   

     //  匹配的 URL Pattern

     private   final  String[] pathPatterns;

   

     //  匹配的 URL Pattern 应该应用的处理器拦截器

     private   final  HandlerInterceptor interceptor;

   

     // 省略了构造器和存取方法

}

有了这些映射信息,处理器映射在构造处理器执行链的时候,就会使用这些信息进行匹配当前的HTTP请求,如果匹配成功,则使用此处理器拦截器。过滤功能是在映射的拦截器集合类中实现的。如下代码注释,

class  MappedInterceptors {

     //  所有可得的映射的拦截器

     private  MappedInterceptor[] mappedInterceptors;

 

     public  MappedInterceptors(MappedInterceptor[] mappedInterceptors) {

         this .mappedInterceptors = mappedInterceptors;

    }

   

     //  通过请求的查找路径进行过滤

     public  Set<HandlerInterceptor> getInterceptors(String lookupPath, PathMatcher pathMatcher) {

        Set<HandlerInterceptor> interceptors =  new  LinkedHashSet<HandlerInterceptor>();

         for  (MappedInterceptor interceptor :  this .mappedInterceptors) {

             //  如果映射的拦截器匹配查找路径,则使用此映射的拦截器

             if  (matches(interceptor, lookupPath, pathMatcher)) {

                interceptors.add(interceptor.getInterceptor());            

            }

        }

         return  interceptors;

    }

   

     private   boolean  matches(MappedInterceptor interceptor, String lookupPath, PathMatcher pathMatcher) {

         //  一个映射的拦截器包含有多个 URL Pattern,  如果其中一个 URL Pattern 匹配查找路径,则匹配成功

        String[] pathPatterns = interceptor.getPathPatterns();

         if  (pathPatterns !=  null ) {

             for  (String pattern : pathPatterns) {

                 if  (pathMatcher.match(pattern, lookupPath)) {

                     return   true ;

                }

            }

             return   false ;

        }  else  {

             return   true ;

        }

    }

   

}

Spring框架实现了一些通用的处理器拦截器。其中,每个拦截器的实现都实现了一个独立完整的逻辑功能。如下类图所示,

 

图表 4‑39

我们已经在前面分析了适配器WebRequestHandlerInterceptorAdapter和HandlerInterceptorAdapter的用途。这里我们将对剩余的类进行功能性的描述,既然,他们的实现并不复杂,这里将不再进行代码注释。

l         WebContentInterceptor

它能用于根据配置设置用户的HTTP缓存,并且对HTTP请求进行简单的方法校验。事实上它是在处理器调用之前对WebContentGenerator的实现进行调用。

l         ConversionServiceExposingInterceptor

它在处理器调用之前导出配置的转换服务到HTTP请求属性中。

l         UserRoleAuthorizationInterceptor

它用于限制一类控制器仅仅可以在一部分的角色中使用。角色校验是在处理器调用之前完成的。

l         LocaleChangeInterceptor

它在处理器调用之前根据请求的地域信息配置地域解析器。

l         ThemeChangeInterceptor

它在处理器调用之前根据请求的主题信息配置主题解析器。

l         PathExposingHandlerInterceptor

处理器内部使用用于导出处理器匹配的路径信息到请求属性中。

l         UriTemplateVariablesHandlerInterceptor

处理器内部使用用于导出处理器匹配的路径信息中的模板变量到请求属性中。

转载请注明出处【 http://sishuok.com/article-detail.html?t=article-121&n=5376 】