springMVC拦截器详解

本文详细介绍了Spring MVC中的拦截器机制,包括HandlerExecutionChain、HandlerInterceptor接口、DispatcherServlet的工作流程以及Servlet的基本原理。讲解了从HTTP请求到DispatcherServlet如何处理,再到HandlerMapping获取HandlerExecutionChain,最后由HandlerAdapter执行并调用拦截器的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HandlerExecutionChain:由HandlerMethod和Interceptor集合组成的类,会被HandlerMapping接口的getHandler方法获取。

HandlerInterceptor接口:Spring拦截器基础接口

AbstractHandlerMapping:HandlerMapping的基础抽象类

AsyncHandlerInterceptor:继承HandlerInterceptor接口,额外提供了afterConcurrentHandlingStarted方法,该方法用来处理异步请求。

 

Web请求被DispatcherServlet截获后,会调用DispatcherServlet的doDispatcher方法。

HandlerExecutionChain mappedHandler = null; mappedHandler = getHandler(processedRequest); HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

首先得到HandlerExecutionChain对象,这个对象包含了HandlerMethod和Interceptors集合,并根据其中的HandlerMethod得到HandlerAdapter。

在HandlerAdapter处理之后,以及处理完成之后会调用HandlerExecutionChain的applyPreHandle、applyPostHandle方法。

 

 

DispatchServlet继承关系

DispatchServlet->FrameworkServlet->HttpServletBean->HttpServlet

HttpServlet

HTTP请求刚进来的时候实际上只是一个HTTP请求报文,容器会自动将这个HTTP请求报文包装成一个HttpServletRequest对象,并且自动调用HttpServlet的service()方法来解析这个请求,service()方法会解析HTTP请求行,而请求行由method、uri、http version三个组成,method就是get或者post,service()方法根据method决定是执行doGet还是doPost,这一切都是服务器Tomcat\jetty自动完成的,HTTP的格式也自动被解析。

只要你的类继承了HttpServlet,并且在web.xml里面配置了相应的servlet和mapping,服务器就会自动帮你执行以上过程。

Servlet框架的核心是javax.servlet.Servlet接口,所有的Servlet都必须实现这一接口,其中有三个方法代表了Servlet的生命周期:

  • init方法,负责初始化Servlet对象
  • service方法,负责相应客户的请求
  • destroy方法,负责释放占有的资源

 

HttpServletBean

HttpServletBean重写了init方法,对初始化流程做了一些处理。主要是:set bean properties from init parameters

1.ServletConfigPropertyValues是HttpServletBean内部静态类,构造过程中会使用ServletConfig对象找出web.xml配置文件中的配置参数并设置到ServletConfigPropertyValues内部

2.使用BeanWrapper构造DispatcherServlet

3.Resource类型参数使用属性编辑器

4.设置DispatcherServlet属性

5.initServletBean()默认实现不做任何处理,子类覆盖该方法可以做任何处理,也就是初始化的时候做更多的事情

<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springConfig/dispatcher-servlet.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>

比如上面这段参数,传递了contextConfigLocation参数,之后构造BeanWrapper,这里使用BeanWrapper有2个理由,1.contextConfigLocation属性在FrameworkServlet中定义,HttpServletBean中无定义。2.利用Spring的注入特性,只需要调用stPropertyValues方法就可将contextConfigLocation属性设置到对应实例中,也就是以依赖注入的方式初始化属性。

然后设置DispatcherServlet的contextConfigLocation属性为web.xml中读取的contextConfigLocation参数,该参数用于构造SpringMVC容器上下文。

 

FrameworkServlet

该类首先覆写了initServletBean方法,如下:

  1. 初始化WebApplicationContext属性,WebApplicationContext是继承自ApplictionContext接口的接口,该属性也就是spring容器上下文。FrameworkServlet的作用就是将Servlet与Spring容器关联。
  2. initFrameworkServlet()默认无处理,主要是为了让子类覆盖做一些需要的处理,不过DispatchServlet并没有覆盖该方法。
  3. rootContext为得到根上下文
  4. DispatcherServlet有个以WebApplicationContext为参数的构造函数,当使用有WebApplicationContext参数的构造函数时使用到if判断这段代码。
  5. wac=findWebApplicationContext(),以contextAttribute属性为key从ServletContext中找WebApplicationContext,一般不会设置contextAttribute属性,也就是这里找到的wac为空。
  6. wac=createWebApplicationContext(rootContext),创建WebApplicationContext上下文,并设置根上下文为父上下文,然后配置ServletConfig,ServletContext等实例到这个上下文中。这个父上下文即web.xml中配置的ContextLoaderListener监听器初始化的容器上下文。
  7. onRefresh(wac),模板方法,WebApplicationContext创建成功之后会调用,FrameworkServlet空实现,子类Dispatcher会覆写该方法。
  8. getServletContext().setAttrubute(attrName,wac),将新创建的容器上下文设置到ServletContext中

 

DispatcherServlet

覆盖了FrameworkServlet中的onRefresh方法:

很明显,initStrategies方法内部会初始化各个策略接口的实现类。比如异常处理初始化initHandlerExceptionResolvers方法,视图处理初始化initViewResolvers方法,请求映射处理初始化initHandlerMappings方法。

 

DispatcherServlet请求处理过程

HttpServlet提供了service方法用于处理请求,service使用了模板设计模式,在内部对于http get会调用doGet方法,http post方法会调用doPost方法。其内部调用了processRequest方法。

  1. 得到与当前请求线程绑定的LocalContext和ServletRequestAttrbutes对象,然后构造新的Local和ServletRequestAttrbutes对象。
  2. 让新构造的LocaleContext和RequestAttributes与当前请求线程绑定(通过ThreadLocal完成)
  3. doService()抽象方法,具体由子类DispatcherServlet实现
  4. resetContextHolders()重置LocaleContext与RequestAttributes对象,重置也就是解除请求线程与LocalContext和RequestAttributes对象的绑定。

继续看DispatcherServlet的doService方法:

  • 如果该请求是include请求,那么保存一份快照版本的request域中的数据,doDispatcher方法结束之后,这个快照版本中的数据将会覆盖新的request域中的数据。
  • request域中设置一些属性
  • doDispatch()最重要的方法。请求分发处理。

首先根据请求的路径找到HandlerMethod(带有Method反射属性,也就是对应Controller中的方法),然后匹配路径对应的拦截器,有了HandlerMethod和拦截器构造个HandlerExecutionChain对象。HandlerExecutionChain对象的获取是通过HandlerMapping接口提供的方法中得到。有了HandlerExecutionChain之后,通过HandlerAdapter对象进行处理得到ModelAndView对象,HandlerMethod内部handle的时候,使用各种HandlerMethodArgumentResolver实现类处理HandlerMethod的参数,使用各种HandlerMethodReturnValueHandler实现类处理返回值。 最终返回值被处理成ModelAndView对象,这期间发生的异常会被HandlerExceptionResolver接口实现类进行处理。

 

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值