springmvc 响应封装_debug方式深入springMVC源码的实现

前言

转载请注明来源

上一次写博客已经是5月份的事了,其实是蛮想抽时间写写,沉淀一下自己,无奈,天天加班加点,人都傻了,心累.真心觉得,对于一个搞技术的人来说,不能只是工作工作,虽然这是必要的(毕竟大多数人还是要吃饭的),但是经常的周期性的沉淀下自己,总结自己一段时间的收获是分重要的.

话不多说了,本篇主要是针对一下springMVC的处理流程及实现原理通过debug方式层层深入理解.

整个篇幅过长,偏向于个人的一个debug过程的展示,以及个人理解的笔记,感兴趣的可以参照我的流程进行debug,加上一些我个人的理解与提示,多debug几遍流程,相信看的人都能得到自己的理解.

服务器原理简介

springMVC作为现在Java这块非常流行的MVC框架,基本上只要会spring就可以无缝衔接springMVC,

那么springMVC到底是如何工作的呢,这里不得不提的是服务器,相信在Java Web这块的程序员们都非常的熟悉.

正好最近撸了点tomcat源码的皮毛,了解了类tomcat等的web服务器的工作原理,有兴趣的可以吃一吃我的安利

<> 这本书.

那么为什么需要服务器呢?

简单来讲,服务器通过ServerSocket获取到Http请求然后对其解析并封装成Request和Response对象,

然后将其交给Servlet容器进行处理,选择对应的Servlet处理请求,返回结果(实际上是很复杂,作为一个web

程序员,这个真的是应该好好了解研究的).

那么为什么tomcat和springmvc可以结合起来呢,最最核心的原因是他们都是基于Servlet规范的,

由于Servlet规范,他们可以互相通信(服务器和SpringMVC的结合在debug时将会简单体现).

SpringMVC

开始详解SpringMVC了.

1、web.xml

web.xml中配置了最重要的ContextLoaderListener以及DispatchServlet.

ContextLoaderListener用于启动web容器时,自动装ApplicationContext的配置信息,

由于 ContextLoaderListener实现了ServletContextListener,所以在web容器启动应用时,

创建ServletContext对象,每个应用都有一个对应的ServletContext对象,ServletContext在应用关闭

时将会销毁,在启动时,可以向ServletContext中添加WebApplicationContext,这个在ServletContext

整个运行期间都是可见的.

DispatchServlet是SpringMVC最重要的一个类,它实现了Servlet,用于对请求做逻辑处理,相应的

ContextLoaderListener实际上只是为了创建WebApplicationContext,DispatchServlet则是负责了

SpringMVC中对客户端请求的逻辑处理,我们的每个请求都是经过DispatchServlet进行处理,调用对应的

逻辑实现(Controller中对应的请求的方法),返回视图,所以说DispatchServlet是SpringMVC中最重要的一个

类一点不为过.

2、启动

终于要接触代码了,下面就对springMVC启动过程的流程与逻辑进行debug。

本文采用的是Jetty服务器.

如下所示,web.xml中配置的监听器类:

image.png

可以看到,该类实现了ServletContextListener,ServletContextListener接口,当系统启动时,将会调用ServletContextListener的实现类的contextInitialized方法,用于在初始化时加入一些属性,这样就可以在全局范围内调用这些属性.

debug启动web工程,直入主题,在contextInitialized方法出打断点:

image.png

继续跳入父类ContextLoader中的initWebApplicationContext方法中进行WebApplicationContext的创建,WebApplicationContext是继承自ApplicationContext,在ApplicationContext的基础上增加了一些特定于Web的操作及属性,详细可以自行查看.

下面是整个initWebApplicationContext方法的详细代码,加入了一点个人理解的注释:

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {

//验证context是否已经存在,

if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {

throw new IllegalStateException(

"Cannot initialize context because there is already a root application context present - " +

"check whether you have multiple ContextLoader* definitions in your web.xml!");

}

Log logger = LogFactory.getLog(ContextLoader.class);

servletContext.log("Initializing Spring root WebApplicationContext");

if (logger.isInfoEnabled()) {

logger.info("Root WebApplicationContext: initialization started");

}

long startTime = System.currentTimeMillis();

try {

// Store context in local instance variable, to guarantee that

// it is available on ServletContext shutdown.

//初始化 WebApplicationContext

if (this.context == null) {

this.context = createWebApplicationContext(servletContext);

}

if (this.context instanceof ConfigurableWebApplicationContext) {

ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;

if (!cwac.isActive()) {

// The context has not yet been refreshed -> provide services such as

// setting the parent context, setting the application context id, etc

if (cwac.getParent() == null) {

// The context instance was injected without an explicit parent ->

// determine parent for root web application context, if any.

ApplicationContext parent = loadParentContext(servletContext);

cwac.setParent(parent);

}

//刷新上下文环境

configureAndRefreshWebApplicationContext(cwac, servletContext);

}

}

//将WebApplicationContext记录在servletContext中

servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

ClassLoader ccl = Thread.currentThread().getContextClassLoader();

if (ccl == ContextLoader.class.getClassLoader()) {

currentContext = this.context;

}

else if (ccl != null) {

//映射当前的类加载器与context实例到全局变量currentContextPerThread中

currentContextPerThread.put(ccl, this.context);

}

if (logger.isDebugEnabled()) {

logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +

WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");

}

if (logger.isInfoEnabled()) {

long elapsedTime = System.currentTimeMillis() - startTime;

logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");

}

return this.context;

}

catch (RuntimeException ex) {

logger.error("Context initialization failed", ex);

servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);

throw ex;

}

catch (Error err) {

logger.error("Context initialization failed", err);

servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);

throw err;

}

}

debug到下图280行,创建WebApplicationContext,

image.png

debug 跳入createWebApplicationContext(servletContext)方法中,

image.png

determineContextClass方法返回一个WebApplicationContext 接口的实现类,否则默认返回XmlWebApplicationContext 或者一个指定的context

image.png

此处有一个defaultStrategies,可以看下图,ContextLoader有一个static代码块,

image.png

image.png

image.png

通过以上我们可以得知,在ContextLoader类加载的时候就先读取了ContextLoader同级目录下的ContextLoader.properties配置文件,在初始化WebApplicationContext时,根据其中的配置提取WebApplicationContext接口的实现类,并根据这个实现类通过反射的方式进行实例的创建.

image.png

接着debug走,将WebApplicationContext记录在servletContext中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值