常见以web.xml配置方式
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>CtrTimeOut</display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <context-param> <param-name>contextConfigLocation</param-name> # spring的配置 <param-value>classpath:config/spring/applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>controller</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> # springmvc的配置 <param-value>classpath:config/spring/spring-controller.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>controller</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
ContextLoadListener创建WebApplicationContext作为spring的容器上下文
#org.springframework.web.context.ContextLoader /** * 根据xml配置创建applicationContext */ public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { ... try { // Store context in local instance variable, to guarantee that // it is available on ServletContext shutdown. if (this.context == null) {//判空 (以注解方式配置时非空) this.context = createWebApplicationContext(servletContext); } if (this.context instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context; if (!cwac.isActive()) { ... //读取contextConfigLocation配置并refresh() configureAndRefreshWebApplicationContext(cwac, servletContext); } } //将applicationContext设置到servletContext中 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); ... return this.context; } }
DispatcherServlet创建WebApplicationContext作为springmvc的上下文 并将ContextLoadListener创建的上下文设置为自身的parent
DispatcherServlet extends FrameworkServlet #org.springframework.web.servlet.FrameworkServlet @Override protected final void initServletBean() throws ServletException { ... try { this.webApplicationContext = initWebApplicationContext(); initFrameworkServlet(); } ... } protected WebApplicationContext initWebApplicationContext() { WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; ... if (wac == null) { //创建applicationContext wac = createWebApplicationContext(rootContext); } ... return wac; } protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) { //XmlWebApplicationContext Class<?> contextClass = getContextClass(); ... //创建applicationContext ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); wac.setEnvironment(getEnvironment()); //设置parent(ContextLoadListener中创建的applicationContext) wac.setParent(parent); //读取contextConfigLocation配置 wac.setConfigLocation(getContextConfigLocation()); //refresh() configureAndRefreshWebApplicationContext(wac); return wac; }
springmvc的applicationContext会去读取配置文件 我们来看一个最简单的配置文件
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd" default-autowire="byName"> #springmvc容器扫描路径 <context:component-scan base-package="com.iflytek.ossp.ctrtimeout.controller"></context:component-scan> #spring4新增的标签 主要是添加了默认的HandleMappin,ViewResolver,HandleAdapter <mvc:annotation-driven /> </beans>
根据spring的自定义schema解析机制 我们找到 在下图位置
http/://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler
可以看到mvc所有的标签解析器都定义在此
public class MvcNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser()); registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser()); 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()); } }
来看一下AnnotationDrivenBeanDefinitionParser解析器做了什么
解析过程较为复杂 通过注释我们可以得知以下对象将被装载
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { ... try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); //1.调用handlerMapping获取handlerChain mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // 2.获取支持该handler解析的HandlerAdapter HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); ... // 3.使用HandlerAdapter完成handler处理 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } // 4.视图处理(页面渲染) applyDefaultViewName(request, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } ... }
过程概括:
上述图片来自网络
定义: 请求路径-处理过程映射管理
打个比方就是根据你的http请求的路径得到可以处理的handler(你的Controller方法)
/** * Interface to be implemented by objects that define a mapping between * requests and handler objects. */ public interface HandlerMapping { //根据request获取处理链 HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; }
以RequestMappingHandlerMapping为例 我们先看下他的继承关系
可以看到有个InitlizingBean(spring的生命周期接口)我们就由他入手
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping //1. @Override public void afterPropertiesSet() { if (this.useRegisteredSuffixPatternMatch) { this.fileExtensions.addAll(this.contentNegotiationManager.getAllFileExtensions()); } super.afterPropertiesSet(); } //4. @Override protected boolean isHandler(Class<?> beanType) { return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) || (AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null)); } //6. @Override protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { RequestMappingInfo info = null; RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class); if (methodAnnotation != null) { //组装映射信息 RequestCondition<?> methodCondition = getCustomMethodCondition(method); info = createRequestMappingInfo(methodAnnotation, methodCondition); RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class); if (typeAnnotation != null) { RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType); info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info); } } return info; } #org.springframework.web.servlet.handler.AbstractHandlerMethodMapping //2. @Override public void afterPropertiesSet() { initHandlerMethods(); } /** * Scan beans in the ApplicationContext, detect and register handler methods. * @see #isHandler(Class) * @see #getMappingForMethod(Method, Class) * @see #handlerMethodsInitialized(Map) */ //3. protected void initHandlerMethods() { if (logger.isDebugEnabled()) { logger.debug("Looking for request mappings in application context: " + getApplicationContext()); } //从容器中获取所有object类型名 String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); for (String beanName : beanNames) { //抽象,过滤(在RequestMappingHandlerMapping中根据Controller和RequestMapping注解过滤) if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) && isHandler(getApplicationContext().getType(beanName))){ //探测类中定义的handler方法 detectHandlerMethods(beanName); } } handlerMethodsInitialized(getHandlerMethods()); } //5. protected void detectHandlerMethods(final Object handler) { Class<?> handlerType = (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass()); final Map<Method, T> mappings = new IdentityHashMap<Method, T>(); final Class<?> userType = ClassUtils.getUserClass(handlerType); //得到符合条件的handler方法 Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() { @Override public boolean matches(Method method) { //抽象,得到映射信息(如RequestMappingInfo) T mapping = getMappingForMethod(method, userType); if (mapping != null) { mappings.put(method, mapping); return true; } else { return false; } } }); //注册handler方法 for (Method method : methods) { registerHandlerMethod(handler, method, mappings.get(method)); } }
上述代码就是HandlerMapping初始化映射关系的代码
来看一下getHandler(Request)的方法实现,看看DispatcherServlet是如何得到处理链的
#org.springframework.web.servlet.handler.AbstractHandlerMapping @Override public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { //抽象,调用子类实现得到一个handler(可以是任一对象,需要通过HandleAdapter来解析) //RequestMappingInfoHandlerMapping中具体实现就是匹配请求路径和RequestMapping注解 Object handler = getHandlerInternal(request); ... //包装handle成HandlerExecutionChain return getHandlerExecutionChain(handler, request); }
定义: 根据HandlerMapping.getHandler()得到的Handler信息,对http请求参数解析并绑定
先看一下HandlerAdapter的接口定义
public interface HandlerAdapter { //判断是否支持该handler类型的解析 boolean supports(Object handler); //参数解析 并调用handler完成过程调用 ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; //用于处理http请求头中的last-modified long getLastModified(HttpServletRequest request, Object handler); }
以RequestMappingHandlerAdapter为例来讲,先看下继承关系
同样看到了实现了InitializingBean接口 从这入手
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter @Override public void afterPropertiesSet() { // 1.初始化ControllerAdvice注解的对象 initControllerAdviceCache(); // 2.装载ArgumentResolver(默认+自定义) if (this.argumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers(); //包装成一个Composite对象 this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } // 2.装载InitBinderArgumentResolvers(默认+自定义) if (this.initBinderArgumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers(); //包装成一个Composite对象 this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } // 3.装载ReturnValueHandlers(默认+自定义) if (this.returnValueHandlers == null) { List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers(); //包装成一个Composite对象 this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); } } private void initControllerAdviceCache() { //从容器中获取所有带有ControllerAdvices注解的类名 并包装成ControllerAdviceBean List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext()); OrderComparator.sort(beans); List<Object> responseBodyAdviceBeans = new ArrayList<Object>(); for (ControllerAdviceBean bean : beans) { //筛选出带有ModelAttribute且不带RequestMapping注解的方法 Set<Method> attrMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS); if (!attrMethods.isEmpty()) { //保存到map中 this.modelAttributeAdviceCache.put(bean, attrMethods); } //筛选出带InitBinder注解的方法 Set<Method> binderMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS); if (!binderMethods.isEmpty()) { //保存到map中 this.initBinderAdviceCache.put(bean, binderMethods); } //如果该类同时实现了ResponseBodyAdvice接口 添加到结合中 if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) { responseBodyAdviceBeans.add(bean); } } //保存到全局变量中 if (!responseBodyAdviceBeans.isEmpty()) { this.responseBodyAdvice.addAll(0, responseBodyAdviceBeans); } }
自定义拓展方式放后面说
以下为HandlerAdapter默认解析器
看一下 HandlerMethodReturnValueHandler 接口和HandlerMethodArgumentResolver接口
//参数解析器 public interface HandlerMethodArgumentResolver { //判断是否支持该参数的解析(根据类型,注解等) boolean supportsParameter(MethodParameter parameter); //对参数进行解析 得到解析结果 Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception; } //返回值解析器 public interface HandlerMethodReturnValueHandler { //判断是否支持该返回值的解析(根据类型,注解等) boolean supportsReturnType(MethodParameter returnType); //对返回值进行解析 void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception; }
上述即HandlerAdapter的初始化过程
//1.调用support()方法判断是否支持改handler的解析 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // 如果是Get或Head请求 调用getLastModified()获取上次更新时间 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; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
#org.springframework.web.servlet.DispatcherServlet //在doDispatch()方法中调用了getHandlerAdapter(Object)方法来得到一个HandlerAdapter protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { //调用HandlerAdapter.support()方法 判断是否支持该handler对象的解析 for (HandlerAdapter ha : this.handlerAdapters) { ... if (ha.supports(handler)) { return ha; } } ... } #org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter @Override public final boolean supports(Object handler) { return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler)); } #org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter @Override protected boolean supportsInternal(HandlerMethod handlerMethod) { return true; }
如果小于浏览器缓存更新时间 则直接返回 浏览器使用本地缓存
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter @Override protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) { return -1; }
#org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter @Override public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler); } #org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter @Override protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { //对http协议缓存方面的请求头的处理(expire,cache-control) if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { // Always prevent caching in case of session attribute management. checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true); } else { // Uses configured default cacheSeconds setting. checkAndPrepare(request, response, true); } // Execute invokeHandlerMethod in synchronized block if required. if (this.synchronizeOnSession) {//是否使用session锁 HttpSession session = request.getSession(false); if (session != null) { //得到互斥量 Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) {//执行过程调用 return invokeHandleMethod(request, response, handlerMethod); } } } //执行过程调用 return invokeHandleMethod(request, response, handlerMethod); } //根据HandlerMethod解析参数 并完成过程调用得到一个ModelAndView private ModelAndView invokeHandleMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); //使用initBinderAdviceCache对@initBinder进行处理 WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); // 使用modelAttributeAdviceCache对@ModelAttribute进行处理 ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory); ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, requestMappingMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); //对异步的处理 暂时不管 TODO后面再分析 ... //1 完成过程调用 requestMappingMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } //2 包装ModelAndView return getModelAndView(mavContainer, modelFactory, webRequest); }
#org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 1.1 参数解析 并完成过程调用 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); ... try { //1.2 使用returnValueHandlers对返回结果进行处理 讲结果塞到mavContainer中 过程类似参数解析 this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } } #org.springframework.web.method.support.InvocableHandlerMethod public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { //1.1.1 参数解析并得到绑定的结果 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); ... //1.1.2 反射完成过程调用 Object returnValue = doInvoke(args); ... return returnValue; } private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { //参数信息 MethodParameter[] parameters = getMethodParameters(); Object[] args = new Object[parameters.length]; for (int i = 0; i < parameters.length; i++) { //调用HandlerMethodArgumentResolver#supportsParameter判断是否支持 if (this.argumentResolvers.supportsParameter(parameter)) { try { //调用HandlerMethodArgumentResolver#resolveArgument进行解析 args[i] = this.argumentResolvers.resolveArgument( parameter, mavContainer, request, this.dataBinderFactory); continue; } ... } ... } return args; }
//从mavContainer取出结果 包装成ModelAndView private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { modelFactory.updateModel(webRequest, mavContainer); if (mavContainer.isRequestHandled()) { return null; } ModelMap model = mavContainer.getModel(); ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model); if (!mavContainer.isViewReference()) { mav.setView((View) mavContainer.getView()); } //如果是redirect请求 if (model instanceof RedirectAttributes) { Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } return mav; }
到此 HandlerAdapter的调用过程算分析完了
springMVC思维导图