Spring MVC 拦截器使用及实现

 1、自定义拦截器
       Spring MVC 也可以使用拦截器对请求进行拦截处理,用户  可以自定义拦截器来实现特定的功能,自定义的拦截器必 须实现HandlerInterceptor接口。
 1)、     HandlerInterceptor接口:

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;

}
  • preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求 request 进行处理。如果程序员决定该拦截器对 请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true;如果程序员决定不需要再调用其他的组件去处理请求,则返回false。
  • postHandle():这个方法在业务处理器处理完请求后,但是DispatcherServlet 向客户端返回响应前被调用,在该方法中对用户请求request进行处理。
  • afterCompletion():这个方法在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
2)自定义拦截器实例 FirstInterceptor 

public class FirstInterceptor implements HandlerInterceptor{
 /**
  * 该方法在目标方法之前被调用.
  * 若返回值为 true, 则继续调用后续的拦截器和目标方法.
  * 若返回值为 false, 则不会再调用后续的拦截器和目标方法.
  *
  * 可以考虑做权限. 日志, 事务等.
  */
 @Override
 public boolean preHandle(HttpServletRequest request,
   HttpServletResponse response, Object handler) throws Exception {
  System.out.println("[FirstInterceptor] preHandle");
  return true;
 }
 /**
  * 调用目标方法之后, 但渲染视图之前.
  * 可以对请求域中的属性或视图做出修改.
  */
 @Override
 public void postHandle(HttpServletRequest request,
   HttpServletResponse response, Object handler,
   ModelAndView modelAndView) throws Exception {
  System.out.println("[FirstInterceptor] postHandle");
 }
 /**
  * 渲染视图之后被调用. 释放资源
  */
 @Override
 public void afterCompletion(HttpServletRequest request,
   HttpServletResponse response, Object handler, Exception ex)
   throws Exception {
  System.out.println("[FirstInterceptor] afterCompletion");
 }
}
自定义拦截器实例 SecondInterceptor 
public class SecondInterceptor implements HandlerInterceptor{
 @Override
 public boolean preHandle(HttpServletRequest request,
   HttpServletResponse response, Object handler) throws Exception {
  System.out.println("[SecondInterceptor] preHandle");
  return true;
 }
 
 @Override
 public void postHandle(HttpServletRequest request,
   HttpServletResponse response, Object handler,
   ModelAndView modelAndView) throws Exception {
  System.out.println("[SecondInterceptor] postHandle");
 }
 
 @Override
 public void afterCompletion(HttpServletRequest request,
   HttpServletResponse response, Object handler, Exception ex)
   throws Exception {
  System.out.println("[SecondInterceptor] afterCompletion");
 }
}
3)自定义拦截器的配置:
<mvc:interceptors>
  <!-- 配置自定义的拦截器FirstInterceptor,拦截所有路径 -->
  <bean class="com.xl.springmvc.interceptor.FirstInterceptor"></bean>
  <!-- 配置拦截器(不)拦截指定的路径 -->
  <mvc:interceptor>
   <mvc:mapping path="/xlxx"/>
   <bean class="com.xl.springmvc.interceptor.SecondInterceptor"></bean>
  </mvc:interceptor>
 </mvc:interceptors>

4)、拦截器执行顺序
        拦截器preHandler返回true情况:
 
        拦截器preHandler返回false情况:

2、拦截器实现
     通过  Spring MVC请求处理流程及架构  已经看到,在Spring MVC处理请求的过程中伴随着 拦截器进行拦截处理的流程,在doDispatch()函数中,执行 mappedHandler = getHandler(processedRequest), 通过 getHandler()方法,使用HandlerMapping完成请求到处理器的映射,获取得到的 HandlerExecutionChain 对象中,不仅包含有Handler处理器,还有 HandlerInterceptor拦截器链,那么这个HandlerExecutionChain是如何包装HandlerInterceptor拦截器链的呢,我们知道HandlerExecutionChain对象是通过调用 HandlerMapping 接口方法 HandlerExecutionChain  getHandler (HttpServletRequest request)得到的, 回到HandlerMapping,以 SimpleUrlHandlerMapping类来看:
 
  
SimpleUrlHandlerMapping类继承体系:



看到HandlerMapping继 承自 WebApplicationObjectSupport进而继承了ApplicationObjectSupport,而ApplicationObjectSupport实现了ApplicationContextAware接口,我们知道,在bean的生命周期中如果该bean类实现了ApplicationContextAware那么通过容器获取这个bean时, void  setApplicationContext (ApplicationContext context)方法将被调用。
 ApplicationObjectSupport类 setApplicationContext()方法:
    
    
@Override
public final void setApplicationContext(ApplicationContext context) throws BeansException {
if (context == null && !isContextRequired()) {
// Reset internal context state.
this.applicationContext = null;
      this.messageSourceAccessor = null;
}
else if (this.applicationContext == null) {
// Initialize with passed-in context.
if (!requiredContextClass().isInstance(context)) {
throw new ApplicationContextException(
"Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
}
this.applicationContext = context;
      this.messageSourceAccessor = new MessageSourceAccessor(context);
    //ApplicationObjectSupport中抽象方法initApplicationContext()
initApplicationContext(context);
}
else {
// Ignore reinitialization if same context passed in.
if (this.applicationContext != context) {
throw new ApplicationContextException(
"Cannot reinitialize with different application context: current one is [" +
this.applicationContext + "], passed-in one is [" + context + "]");
}
   }
}
void initApplicationContext()是一个抽象方法,留给子类实现具体初始化功能,而AbstractHandlerMapping类重写了该方法:
@Override
protected void initApplicationContext() throws BeansException {
   extendInterceptors(this.interceptors);
//探测容器中所有拦截器
detectMappedInterceptors(this.mappedInterceptors);
//初始配置这些拦截器
initInterceptors();
}
看到在重写的这个initApplicationContext()方法中,进行了拦截器相关的探测以及初始化设置:
   
   
protected void detectMappedInterceptors(List<MappedInterceptor> mappedInterceptors) {
   mappedInterceptors.addAll(
    //通过BeanFactoryUtils工具类,获取ioc容器中所有的MappedInterceptor类的bean
         BeanFactoryUtils.beansOfTypeIncludingAncestors(
               getApplicationContext(), MappedInterceptor.class, true, false).values());
}
在完成了拦截器对象的获取后,对这些拦截器分别进行初始化配置,最终保存到AbstractHandlerMapping类成员变量
mappedInterceptors和adaptedInterceptors中,以便后用
protected void initInterceptors() {
if (!this.interceptors.isEmpty()) {
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");
}
if (interceptor instanceof MappedInterceptor) {
this.mappedInterceptors.add((MappedInterceptor) interceptor);
}
else {
this.adaptedInterceptors.add(adaptInterceptor(interceptor));
}
      }
   }
}
经过以上过程,Spring MVC容器中配置的拦截器都已经初始化设置到HandlerMapping Bean对象中,当调用getHandler方法时:
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
 // 根据request请求映射获取对应的Handler
  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);
}
  //获取HandlerExecutionChain

return getHandlerExecutionChain(handler, request);
}
继续看getHandlerExecutionChain()方法,获取HandlerExecutionChain
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
   //如果handler 已经是HandlerExecutionChain 实例那么直接使用,否则创建新的HandlerExecutionChain 
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
         (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
chain.addInterceptors(getAdaptedInterceptors());

String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
//逐个遍历mappedInterceptors,将匹配请求路径的Interceptor加入HandlerExecutionChain中 

   for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) {
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
         chain.addInterceptor(mappedInterceptor.getInterceptor());
}
   }

return chain;
}
到此, HandlerExecutionChain 获取完成,拦截器也已经包装到该对象中,可以用于在请求流程中进行拦截处理。

然而还有一个重要的问题,就是这些拦截器是如何配置到IoC容器中的呢,在自定义拦截器部分我们看到,通过<mvc:interceptors>标签,将我们自定义的拦截器配置到xml文件中。当Ioc容器解析BeanDefinition遇到<mvc:interceptors>这个标签,将使用自定义标签解析机制处理这些标签。 MvcNamespaceHandler类用于加载与Spring MVC模块相关的自定义标签解析器:
   
   
public class MvcNamespaceHandler extends NamespaceHandlerSupport {

@Override
public void init() {
      registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
  //这里注册<mvc:default-servlet-handlerv>标签解析器,该标签主要用与处理静态资源
registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
    //这里注册<mvc:interceptors>标签解析器
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("velocity-configurer", new VelocityConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
}

}
在看DefaultServletHandlerBeanDefinitionParser类,该类核心函数 BeanDefinition  parse (Element element ParserContext parserContext)如下:

   
   
class InterceptorsBeanDefinitionParser implements BeanDefinitionParser {

@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
      CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compDefinition);

RuntimeBeanReference pathMatcherRef = null;
      if (element.hasAttribute("path-matcher")) {
         pathMatcherRef = new RuntimeBeanReference(element.getAttribute("path-matcher"));
}

      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;
}
通过以上解析函数,解析配置文件中 <mvc:interceptors>范围内所有拦截器配置,并转为BeanDefinition,最终注册得到Ioc容器中。







  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值