欢迎访问 生活随笔!

凯发k8官方网

当前位置: 凯发k8官方网 > 前端技术 > javascript >内容正文

javascript

spring mvc原理-凯发k8官方网

发布时间:2024/10/8 javascript 0 豆豆
凯发k8官方网 收集整理的这篇文章主要介绍了 spring mvc原理_spring mvc的工作原理,我们来看看其源码实现 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

来源:https://www.cnblogs.com/youzhibing/p/10695012.html

作者:youzhibing2904

遗留问题

在关于利用maven搭建ssm的博客,我们一起来探讨下问的最多的问题中,我遗留了一个问题:spring mvc是何时、何地、如何将model中的属性绑定到哪个作用域,这里的作用域指的是servlet的四大作用域;不了解问题背景的可以回过头去看看我的上篇博文。

明确的解答我会放到最后,在解答问题之前,我先和大家一起来捋一捋spring mvc的工作原理。废话不多说,开始我们神秘的探险之旅!

在讲工作原理之前,我们先看一个简单的spring mvc(ssm)示例,以及实现的效果

工程代码地址:ssm-web 

工程结构与效果如上所示,我们不做过多的探究,我们打起精神往下看本篇的重点

准备 - 资源的加载与初始化

1、dispatcherservlet 静态初始化

dispatcherservlet中有如下静态块

static { // load default strategy implementations from properties file. // this is currently strictly internal and not meant to be customized // by application developers. try { classpathresource resource = new classpathresource(default_strategies_path, dispatcherservlet.class); defaultstrategies = propertiesloaderutils.loadproperties(resource); } catch (ioexception ex) { throw new illegalstateexception("could not load 'dispatcherservlet.properties': " ex.getmessage()); } }

这里会将dispatcherservlet.properties中的内容读取到dispatcherservlet的属性:private static final properties defaultstrategies中,dispatcherservlet.properties内容如下

# default implementation classes for dispatcherservlet's strategy interfaces.# used as fallback when no matching beans are found in the dispatcherservlet context.# not meant to be customized by application developers.org.springframework.web.servlet.localeresolver=org.springframework.web.servlet.i18n.acceptheaderlocaleresolverorg.springframework.web.servlet.themeresolver=org.springframework.web.servlet.theme.fixedthemeresolverorg.springframework.web.servlet.handlermapping=org.springframework.web.servlet.handler.beannameurlhandlermapping, org.springframework.web.servlet.mvc.annotation.defaultannotationhandlermappingorg.springframework.web.servlet.handleradapter=org.springframework.web.servlet.mvc.httprequesthandleradapter, org.springframework.web.servlet.mvc.simplecontrollerhandleradapter, org.springframework.web.servlet.mvc.annotation.annotationmethodhandleradapterorg.springframework.web.servlet.handlerexceptionresolver=org.springframework.web.servlet.mvc.annotation.annotationmethodhandlerexceptionresolver, org.springframework.web.servlet.mvc.annotation.responsestatusexceptionresolver, org.springframework.web.servlet.mvc.support.defaulthandlerexceptionresolverorg.springframework.web.servlet.requesttoviewnametranslator=org.springframework.web.servlet.view.defaultrequesttoviewnametranslatororg.springframework.web.servlet.viewresolver=org.springframework.web.servlet.view.internalresourceviewresolverorg.springframework.web.servlet.flashmapmanager=org.springframework.web.servlet.support.sessionflashmapmanager

指定了dispatcherservlet策略接口的默认实现,后续dispatcherservlet初始化策略的时候会用到

2、interceptor定义的加载

spring启动过程中会调用interceptorsbeandefinitionparser的parse方法来解析出我们自定义的interceptor定义,封装成mappedinterceptor类型的bean定义,并放到spring容器中;我们可以简单的认为spring容器中已经存在了我们自定义的interceptor的bean定义

3、dispatcherservlet初始化策略:initstrategies

dispatcherservlet的继承图如下

dispatcherservlet是一个servlet,tomcat启动过程中会调用其init方法,一串的调用后,会调用dispatcherservlet的initstrategies方法

protected void initstrategies(applicationcontext context) {

initmultipartresolver(context);

initlocaleresolver(context);

initthemeresolver(context);

inithandlermappings(context);

inithandleradapters(context);

inithandlerexceptionresolvers(context);

initrequesttoviewnametranslator(context);

initviewresolvers(context);

initflashmapmanager(context);

}

实例化步骤1中的默认实现,并填充到dispatcherservlet各个属性值中

4、defaultannotationhandlermapping的拦截器初始化

dispatcherservlet.properties种指定了两个默认的handlermapping:beannameurlhandlermapping、defaultannotationhandlermapping,这两者的类继承图如下(我们暂时只关注defaultannotationhandlermapping)

defaultannotationhandlermapping间接实现了applicationcontextaware,那么在defaultannotationhandlermapping实例初始化过程中,会调用setapplicationcontext(applicationcontext applicationcontext)方法,一串调用后,会来到abstracturlhandlermapping的initapplicationcontext()

@overrideprotected void initapplicationcontext() throws beansexception { extendinterceptors(this.interceptors); detectmappedinterceptors(this.mappedinterceptors); initinterceptors();}

初始化了defaultannotationhandlermapping的拦截器:interceptor

我们来看下具体的初始化过程,看看上面的顺序是否只是我个人的臆想?

可以看到,初始化顺序就是我们上面说的,不是我个人的意淫;此时的defaultannotationhandlermapping中有我们自定义的myinterceptor。初始化过程我们需要关注的就是上述这些,下面我们一起看看具体请求的过程

请求的处理

请求从servlet的service开始,一路到dispatcherservlet的dodispatch,如下图

/** * process the actual dispatching to the handler. 将请求分发到具体的handler,也就是我们的controller *

the handler will be obtained by applying the servlet's handlermappings in order. * the handleradapter will be obtained by querying the servlet's installed handleradapters * to find the first that supports the handler class. *

all http methods are handled by this method. it's up to handleradapters or handlers * themselves to decide which methods are acceptable. * @param request current http request * @param response current http response * @throws exception in case of any kind of processing failure */protected void dodispatch(httpservletrequest request, httpservletresponse response) throws exception { httpservletrequest processedrequest = request; handlerexecutionchain mappedhandler = null; boolean multipartrequestparsed = false; webasyncmanager asyncmanager = webasyncutils.getasyncmanager(request); try { modelandview mv = null; exception dispatchexception = null; try { processedrequest = checkmultipart(request); multipartrequestparsed = processedrequest != request; // determine handler for the current request. 决定哪个handler来处理当前的请求 // mappedhandler是由handler和interceptor集合组成的一个执行链,有点类似filterchain mappedhandler = gethandler(processedrequest); if (mappedhandler == null || mappedhandler.gethandler() == null) { nohandlerfound(processedrequest, response); return; } // determine handler adapter for the current request. 决定哪个adapter来处理当前的请求 // handlermapping是找出适配的handler,而真正回调handler的是adapter handleradapter ha = gethandleradapter(mappedhandler.gethandler()); // process last-modified header, if supported by the handler. string method = request.getmethod(); boolean isget = "get".equals(method); if (isget || "head".equals(method)) { long lastmodified = ha.getlastmodified(request, mappedhandler.gethandler()); if (logger.isdebugenabled()) { string requesturi = urlpathhelper.getrequesturi(request); logger.debug("last-modified value for [" requesturi "] is: " lastmodified); } if (new servletwebrequest(request, response).checknotmodified(lastmodified) && isget) { return; } } // handler的前置处理,也就是调用适配当前url的interceptor的prehandler方法 if (!mappedhandler.applyprehandle(processedrequest, response)) { return; } try { // actually invoke the handler. 真正调用handler mv = ha.handle(processedrequest, response, mappedhandler.gethandler()); } finally { if (asyncmanager.isconcurrenthandlingstarted()) { return; } } applydefaultviewname(request, mv); // handler的后置处理,也就是调用适配当前url的interceptor的posthandler方法 mappedhandler.applyposthandle(processedrequest, response, mv); } catch (exception ex) { dispatchexception = ex; } // 处理handler返回的结果,会调用适配当前url的interceptor的aftercompletion方法 // 这里会将响应结果返回给请求者 processdispatchresult(processedrequest, response, mappedhandler, mv, dispatchexception); } catch (exception ex) { triggeraftercompletion(processedrequest, response, mappedhandler, ex); } catch (error err) { triggeraftercompletionwitherror(processedrequest, response, mappedhandler, err); } finally { if (asyncmanager.isconcurrenthandlingstarted()) { // instead of posthandle and aftercompletion mappedhandler.applyafterconcurrenthandlingstarted(processedrequest, response); return; } // clean up any resources used by a multipart request. if (multipartrequestparsed) { cleanupmultipart(processedrequest); } }}

handlermapping具体如何找到匹配当前url的handler(一般而言就是我们的controller)、handleradapter具体如何回调真正的handler,有兴趣的可以自行去跟下,我就不跟了。我们具体看下processdispatchresult(processedrequest, response, mappedhandler, mv, dispatchexception); 这个与我们最初的疑问有关

processdispatchresult

可以看到model中的persons会被设置到request的attributes中,然后转发请求到show_person.jsp,转发过程中request作用域的变量仍然有效,所以show_person.jsp中的jstl标签和el表达式能够取到persons变量,最后将show_person.jsp中的内容填充好之后的静态内容返回给请求者;至此就完成了一次请求的响应

回到我们开篇的疑问:spring mvc是何时、何地、如何将model中的属性绑定到哪个作用域?想必大家已经知道答案了

controller中的model、modelmap的注入由spring mvc完成,这个不是请求传入的参数,用于绑定变量到servlet作用域;默认情况下,在dispatcherservlet调用了真正的handler之后,将结果返回给请求者的过程中,将model、modelmap中的变量设置到了request的attributes中,转发的过程中,request中的变量仍然有效,所以show_person.jsp中能取到persons这个变量,自此疑问得到解答

1、spring mvc工作原理图

图是用的别人的,具体是谁的我也不记得了(捂脸)

2、defaultannotationhandlermapping在spring3.2中被废弃,替换成了requestmappinghandlermapping

总结

以上是凯发k8官方网为你收集整理的spring mvc原理_spring mvc的工作原理,我们来看看其源码实现的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得凯发k8官方网网站内容还不错,欢迎将凯发k8官方网推荐给好友。

  • 上一篇:
  • 下一篇:
网站地图