一、SpringMVC使用1。工程创建创建maven工程。添加java、resources目录。引入Springwebmvc依赖。dependencygroupIdorg。springframeworkgroupIdspringwebmvcartifactIdversion5。3。4versiondependency删除srcmainwebappWEBINFweb。xml配置文件。从tomcat的示例工程中找一份web。xml替换,这里推荐从webappsROOTWEBINF中拿,并且在其中添加context的监听器和servlet配置,配置如下。!Context加载监听器listenerlistenerclassorg。springframework。web。context。ContextLoaderListenerlistenerclasslistenerservletservletnamedispatcherServletservletnameservletclassorg。springframework。web。servlet。DispatcherServletservletclassinitparamparamnamecontextConfigLocationparamnameparamvalueclasspath:application。xmlparamvalueinitparam!Web服务器一旦启动,Servlet就会实例化创建对象,然后初始化(预备创建对象)loadonstartup1loadonstartupservletservletmappingservletnamedispatcherServletservletnameurlpatternurlpatternservletmapping在resources目录中创建springmvc。xml文件,并添加如下配置:?xmlversion1。0encodingUTF8?beansxmlnshttp:www。springframework。orgschemabeansxmlns:xsihttp:www。w3。org2001XMLSchemainstancexmlns:contexthttp:www。springframework。orgschemacontextxmlns:mvchttp:www。springframework。orgschemamvcxsi:schemaLocationhttp:www。springframework。orgschemabeanshttp:www。springframework。orgschemabeansspringbeans。xsdhttp:www。springframework。orgschemacontexthttp:www。springframework。orgschemacontextspringcontext。xsdhttp:www。springframework。orgschemamvchttps:www。springframework。orgschemamvcspringmvc。xsd!配置spring包扫描路径,被Component、Controller、Service、Repository标注的类都会交由Spring托管一个Beancontext:componentscanbasepackagecom。ybe。!配置视图解析器beanclassorg。springframework。web。servlet。view。InternalResourceViewResolverpropertynameprefixvaluepropertynamesuffixvalue。jsppropertybeanbeans在srcmainwebappWEBINF下添加applicationContext。xml文件,配置如下:?xmlversion1。0encodingUTF8?beansxmlnshttp:www。springframework。orgschemabeansxmlns:xsihttp:www。w3。org2001XMLSchemainstancexmlns:contexthttp:www。springframework。orgschemacontextxmlns:mvchttp:www。springframework。orgschemamvcxsi:schemaLocationhttp:www。springframework。orgschemabeanshttp:www。springframework。orgschemabeansspringbeans。xsdhttp:www。springframework。orgschemacontexthttp:www。springframework。orgschemacontextspringcontext。xsdhttp:www。springframework。orgschemamvchttps:www。springframework。orgschemamvcspringmvc。xsdbeans创建Controller类,代码如下:packagecom。ybe。importorg。springframework。stereotype。Cimportorg。springframework。web。bind。annotation。RequestMControllerpublicclassHelloController{RequestMapping(hello)publicStringhelloWorld(){System。out。println(helloworld);}}2。工程配置点击AddConfigurations或者RunAddConfigurations。配置本地tomcat的目录配置浏览器地址,点击上图左上角的号,选择TomcatServer选项后,点击Deployment选项,点击右边的号。选择Artifacts后,选择springMvcTest:war。3。启动工程 二、SpringMVC启动过程 SpringMVC是依赖Java的Web容器技术,整个springmvc的启动过程是建立在Servlet技术基础上的。SpringMVC借助Web容器和Servelt的生命周期进行了扩展。父容器的初始化在ContextLoaderListener类中initWebApplicationContext方法进行,子容器的初始化在DispatcherServlet中init方法中进行。1。父容器启动过程 如果web。xml中配置了ContextLoaderListener监听器,则web容器启动的时候先会调用监听器ContextLoaderListener的initWebApplicationContext方法。整个过程如下图: initWebApplicationContext中的整个过程就是创建了一个spring容器(父容器),并且根据springApplication。xml的配置内容往Spring容器中注入Bean对象。最后把spring容器(this。context对象)放入serveltContext的属性中。2。子容器启动过程(SpringMvc容器) DispatcherServlet是在web。xml配置文件中配置的Servlet类,是SpringMVC的请求分发核心类。所有的请求都由DispatcherServlet去分发处理。 DispatcherServlet的继承关系如下图: 上图可知DispatcherServlet继承了HttpServletBean。在HttpServletBean中重写了init(),Web容器启动的时候会根据配置文件中定义的Servlet进行创建,并且会根据配置项(loadonstartup)觉定在什么时候调用Servlet的init方法,init方法在整个Servlet的生命周期中只会调用一次。初始化init方法的主体实现过程如下: 1。WebApplicationContextUtils。getWebApplicationContext(getServletContext())从ServletContext中获取属性为WebApplicationContext。ROOTWEBAPPLICATIONCONTEXTATTRIBUTE的对象,即Spring父容器对象。 2。wac。addApplicationListener(newSourceFilteringListener(wac,newContextRefreshListener())),给子容器添加应用监听器,该监听器在后面的finishRefresh()方法中进行触发,方法里面封装了初始化SpringMVC中九大组件的逻辑。 3。publishEvent(newContextRefreshedEvent(this))发布Context刷新事件,会触发SourceFilteringListener监听器,最终进行initStrategies的调用。3。九大组件的初始化 initStrategies是SpringMVC中九大组件的初始化方法其中9个方法对应9个组件的初始化,本文中只讲映射器和适配器的创建过程,initStrategies代码如下:初始化MultipartResolver:主要用来处理文件上传。如果定义过当前类型的bean对象,那么直接获取,如果没有的话,可以为nullinitMultipartResolver(context);初始化LocaleResolver:主要用来处理国际化配置,基于URL参数的配置(AcceptHeaderLocaleResolver),基于session的配置(SessionLocaleResolver),基于cookie的配置(CookieLocaleResolver)initLocaleResolver(context);初始化ThemeResolver:主要用来设置主题ThemeinitThemeResolver(context);初始化HandlerMapping:映射器,用来将对应的request跟controller进行对应initHandlerMappings(context);初始化HandlerAdapter:处理适配器,主要包含Http请求处理器适配器,简单控制器处理器适配器,注解方法处理器适配器initHandlerAdapters(context);初始化HandlerExceptionResolver:基于HandlerExceptionResolver接口的异常处理initHandlerExceptionResolvers(context);初始化RequestToViewNameTranslator:当controller处理器方法没有返回一个View对象或逻辑视图名称,并且在该方法中没有直接往response的输出流里面写数据的时候,spring将会采用约定好的方式提供一个逻辑视图名称initRequestToViewNameTranslator(context);初始化ViewResolver:将ModelAndView选择合适的视图进行渲染的处理器initViewResolvers(context);初始化FlashMapManager:提供请求存储属性,可供其他请求使用initFlashMapManager(context);1。处理器映射器的初始化 1。initHandlerMappings初始化映射器,在此方法中第一步会获取容器中实现了HandlerMapping的Bean对象,如果有则用自定义的HandlerMapping实现类作为this。handlerMappings的值;如果没有自定义类,则获取SpringMVC预先定义好的策略类。代码流程如下: 2。ClassPathResourceresourcenewClassPathResource(DEFAULTSTRATEGIESPATH,DispatcherServlet。class);获取DispatcherServlet。properties资源文件,位置在springwebmvc中,路径resourcesorgspringframeworkwebservletDispatcherServlet。properties,该资源文件中定义了SpringMVC组件的默认实现策略类,具体内容如下:DefaultimplementationclassesforDispatcherServletsstrategyinterfaces。UsedasfallbackwhennomatchingbeansarefoundintheDispatcherServletcontext。Notmeanttobecustomizedbyapplicationdevelopers。org。springframework。web。servlet。LocaleResolverorg。springframework。web。servlet。i18n。AcceptHeaderLocaleResolverorg。springframework。web。servlet。ThemeResolverorg。springframework。web。servlet。theme。FixedThemeResolverorg。springframework。web。servlet。HandlerMappingorg。springframework。web。servlet。handler。BeanNameUrlHandlerMapping,org。springframework。web。servlet。mvc。method。annotation。RequestMappingHandlerMapping,org。springframework。web。servlet。function。support。RouterFunctionMappingorg。springframework。web。servlet。HandlerAdapterorg。springframework。web。servlet。mvc。HttpRequestHandlerAdapter,org。springframework。web。servlet。mvc。SimpleControllerHandlerAdapter,org。springframework。web。servlet。mvc。method。annotation。RequestMappingHandlerAdapter,org。springframework。web。servlet。function。support。HandlerFunctionAdapterorg。springframework。web。servlet。HandlerExceptionResolverorg。springframework。web。servlet。mvc。method。annotation。ExceptionHandlerExceptionResolver,org。springframework。web。servlet。mvc。annotation。ResponseStatusExceptionResolver,org。springframework。web。servlet。mvc。support。DefaultHandlerExceptionResolverorg。springframework。web。servlet。RequestToViewNameTranslatororg。springframework。web。servlet。view。DefaultRequestToViewNameTranslatororg。springframework。web。servlet。ViewResolverorg。springframework。web。servlet。view。InternalResourceViewResolverorg。springframework。web。servlet。FlashMapManagerorg。springframework。web。servlet。support。SessionFlashMapManager 由内容可知HandlerMapping预制的策略类有BeanNameUrlHandlerMapping、RequestMappingHandlerMapping、RouterFunctionMapping,其中RequestMappingHandlerMapping是我们常用的HandlerMapping对象。 3。RequestMappingHandlerMapping的初始化,因为RequestMappingHandlerMapping实现了InitializingBean接口,所以在容器中初始化完之后会执行afterPropertiesSet方法,其中会调用super。afterPropertiesSet();父类为AbstractHandlerMethodMapping。此方法中会调用initHandlerMethods(),代码如下:protectedvoidinitHandlerMethods(){遍历Bean,逐个处理for(StringbeanName:getCandidateBeanNames()){排除目标代理类,AOP相关,可查看注释if(!beanName。startsWith(SCOPEDTARGETNAMEPREFIX)){处理BeanprocessCandidateBean(beanName);}}初始化处理器的方法们,目前没有特殊业务逻辑,只是打印ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志ahandlerMethodsInitialized(getHandlerMethods());} 4。processCandidateBean方法中会判断BeanName的Bean是否有Controller。class或者RequestMapping。class注解来生成具体的HandlerMethod对象。2。处理器适配器的初始化 1。initHandlerAdapters适配器初始化,过程和映射器相似。从上面的内容可知HandlerAdapter与之的策略类有HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、RequestMappingHandlerAdapter、HandlerFunctionAdapter。其中RequestMappingHandlerAdapter是我们常用的处理器适配器。 2。RequestMappingHandlerAdapter实现了InitializingBean接口,在容器中初始化完之后会调用afterPropertiesSet方法,在此方法中会初始化参数解析器、绑定参数解析器、返回值解析器。此方法代码如下:OverridepublicvoidafterPropertiesSet(){Dothisfirst,itmayaddResponseBodyadvicebeans初始化注释了ControllerAdvice的类的相关属性initControllerAdviceCache();初始化argumentResolvers属性if(this。argumentResolversnull){ListHandlerMethodArgumentResolverresolversgetDefaultArgumentResolvers();this。argumentResolversnewHandlerMethodArgumentResolverComposite()。addResolvers(resolvers);}初始化initBinderArgumentResolvers属性if(this。initBinderArgumentResolversnull){ListHandlerMethodArgumentResolverresolversgetDefaultInitBinderArgumentResolvers();this。initBinderArgumentResolversnewHandlerMethodArgumentResolverComposite()。addResolvers(resolvers);}初始化returnValueHandlers属性if(this。returnValueHandlersnull){ListHandlerMethodReturnValueHandlerhandlersgetDefaultReturnValueHandlers();this。returnValueHandlersnewHandlerMethodReturnValueHandlerComposite()。addHandlers(handlers);}}4。拦截器的初始化 因为所有的HandlerMapping预制的策略类都继承了AbstractHandlerMapping,而AbstractHandlerMapping实现了ApplicationContextAware接口,所以在具体的HandlerMapping策略类初始化完之后会调用initApplicationContext方法,该方法中具体实现了拦截器的创建,代码如下:protectedvoidinitApplicationContext()throwsBeansException{空实现,交给子类实现,用于注册自定义的拦截器到interceptors中,目前暂无子类实现extendInterceptors(this。interceptors);扫描已注册的MappedInterceptor的Bean们,添加到adaptedInterceptors中detectMappedInterceptors(this。adaptedInterceptors);将interceptors初始化成HandlerInterceptor类型,添加到adaptedInterceptors中initInterceptors();}三、SpringMVC请求过程1。请求流程图 2。业务描述 1。请求进来后会调用FrameworkServlet的service()方法,该方法中会调用(HttpServlet)super。service方法,其中会调用doXXX()方法,而doXXX()方法在FrameworkServlet重写,每个doXXX()方法中又会调用processRequest(request,response)方法,processRequest中会调用doService(),doService()中又会调用doDispatch(),整个业务处理逻辑定义在doDispatch方法中。 2。循环遍历在启动过程中创建的handlerMapping处理器映射器集合查找对应处理器,传入参数为request请求对象,返回的是HandlerExecutionChain类型的对象,代码如下protectedHandlerExecutionChaingetHandler(HttpServletRequestrequest)throwsException{if(this。handlerMappings!null){遍历for(HandlerMappingmapping:this。handlerMappings){HandlerExecutionChainhandlermapping。getHandler(request);if(handler!null){}}}} 在getHandler方法中如果找到具体的handler对象(HandlerMethod类型),会继续封装handler对象为一个executionChain处理器链链对象(HandlerExecutionChain类型),代码如下:ObjecthandlergetHandlerInternal(request);if(handlernull){handlergetDefaultHandler();}如果handler为null即返回null。说明当前的处理器映射器不匹配。if(handlernull){}Beannameorresolvedhandler?if(handlerinstanceofString){StringhandlerName(String)handlerobtainApplicationContext()。getBean(handlerName);}EnsurepresenceofcachedlookupPathforinterceptorsandothersif(!ServletRequestPathUtils。hasCachedPath(request)){initLookupPath(request);}创建处理器链HandlerExecutionChainexecutionChaingetHandlerExecutionChain(handler,request); getHandlerInternal是多态方法,具体的实现类中有不同的实现方式。查找具体的HandlerMethod逻辑比较复杂,请自行查看源码。 3。循环遍历在启动过程中创建的handlerAdapters处理器适配器集合查找对应处理器适配器,传入参数为handler处理器对象,返回的是RequestMappingHandlerAdapter类型的处理器适配器,代码如下:protectedHandlerAdaptergetHandlerAdapter(Objecthandler)throwsServletException{if(this。handlerAdapters!null){循环判断哪个适配器能处理传入的处理器for(HandlerAdapteradapter:this。handlerAdapters){if(adapter。supports(handler)){}}}thrownewServletException(Noadapterforhandler〔handler〕:TheDispatcherServletconfigurationneedstoincludeaHandlerAdapterthatsupportsthishandler);} 4。循环执行mappedHandler(HandlerExecutionChain拦截器链)对象的拦截器preHandle方法。 5。处理器适配器调用处理方法,最终会执行ServletInvocableHandlerMethod。invokeAndHandle()方法,此方法中会调用invokeForRequest,invokeForRequest中会先拿到Controller中方法的具体参数值,再执行该方法,最后会返回ModelAndView对象。 6。循环执行mappedHandler(HandlerExecutionChain拦截器链)对象的拦截器postHandle方法。 7。processDispatchResult方法中会先查找找到具体的视图引擎,代码如下:protectedViewresolveViewName(StringviewName,NullableMapString,Objectmodel,Localelocale,HttpServletRequestrequest)throwsException{if(this。viewResolvers!null){for(ViewResolverviewResolver:this。viewResolvers){ViewviewviewResolver。resolveViewName(viewName,locale);if(view!null){}}}} 然后渲染视图内容,底层其实就是请求的转发,代码如下:publicvoidrender(NullableMapString,?model,HttpServletRequestrequest,HttpServletResponseresponse)throwsException{if(logger。isDebugEnabled()){logger。debug(ViewformatViewName(),model(model!null?model:Collections。emptyMap())(this。staticAttributes。isEmpty()?:,staticattributesthis。staticAttributes));}合并返回结果,将Model中的静态数据和请求中的动态数据进行合并MapString,ObjectmergedModelcreateMergedOutputModel(model,request,response);prepareResponse(request,response);进行渲染renderMergedOutputModel(mergedModel,getRequestToExpose(request),response);} 8。循环执行mappedHandler(HandlerExecutionChain拦截器链)对象的拦截器afterCompletion方法。