热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Spring源码阅读(九)—SpringMVC的初始化

Spring源码阅读(九)—SpringMVC的初始化本文主要整理了Web应用启动时具体的初始化流程,包括Spring上下文的的初始化和SpringMVC的初始化个人主页:

Spring源码阅读(九)—SpringMVC的初始化

本文主要整理了Web应用启动时具体的初始化流程,包括Spring上下文的的初始化和SpringMVC的初始化

个人主页:tuzhenyu’s page
原文地址:Spring源码阅读(九)—SpringMVC的初始化

(1) SpringMVC的初始化

SpringMVC的初始化是从Web容器如Tomcat,Jetty等启动时加载解析web.xml文件开始的,初始化只要包括两部分:

  • ContextLoaderListener初始化

  • DispatcherServlet的初始化

(2) ContextLoaderListener初始化

ContextLoaderListener初始化的主要功能是将在Web应用启动时,自动装配ApplicationContext上下文环境,将Spring的IOC,AOP等功能与Web环境结合起来;每个Web应用都有一个ServletContext与之相关联作为整个Web应用的全局变量的存放地,ContextLoaderListener的核心逻辑就是初始化WebApplicationContext实例并将之放在servletContext中.

  • 使用ContextLoaderListener初始化之前需要设定Spring的配置文件地址
param>
<param-name>contextConfigLocationparam-name>
<param-value>/WEB-INF/applicationContext.xmlparam-value>
param>
  • 注册ContextLoaderListener监听器,在Web容器启动时会创建并初始化该监听器
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
  • ContextLoaderListener监听器实现了ServletContextListener接口对ServletContext进行监听,当ServletContext创建后会调用其contextInitialized()方法对ServletContext进行初始化;在contextInitialized()方法中会调用initWebApplicationContext()方法初始化WebApplicationContext上下文环境.
public void contextInitialized(ServletContextEvent event) {
this.initWebApplicationContext(event.getServletContext());
}
  • initWebApplicationContext()方法调用createWebApplicationContext()方法创建上下文环境对象,调用

configureAndRefreshWebApplicationContext()方法对上下文进行初始化(refresh),并将其记录在servletContext中

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
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!");
} else {
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 {
if(this.cOntext== null) {
this.cOntext= this.createWebApplicationContext(servletContext);
}

if(this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext err = (ConfigurableWebApplicationContext)this.context;
if(!err.isActive()) {
if(err.getParent() == null) {
ApplicationContext elapsedTime = this.loadParentContext(servletContext);
err.setParent(elapsedTime);
}

this.configureAndRefreshWebApplicationContext(err, servletContext);
}
}

servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
ClassLoader err1 = Thread.currentThread().getContextClassLoader();
if(err1 == ContextLoader.class.getClassLoader()) {
currentCOntext= this.context;
} else if(err1 != null) {
currentContextPerThread.put(err1, 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 elapsedTime1 = System.currentTimeMillis() - startTime;
logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime1 + " ms");
}

return this.context;
} catch (RuntimeException var8) {
logger.error("Context initialization failed", var8);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var8);
throw var8;
} catch (Error var9) {
logger.error("Context initialization failed", var9);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var9);
throw var9;
}
}
}
  • ServletContextListener创建ApplicationContext上下文环境主要包括以下几步:

    • 在创建的过程中,会提取将要实现的WebApplicationContext接口的实现类,再根据这个实现类通过forName()反射的方式进行实例的创建;

    • 将配置的contextConfigLocation参数(即Spring配置文件applicationContext.xml)传入ApplicationContext对象并调用refresh()方法刷新Spring容器,完成Spring容器的创建和启动;

    • 将创建好的ApplicationContext放入ServletContext中;

(3) DispatcherServlet的初始化

DispatcherServlet实现了Servlet接口,并且在web.xml配置中load-on-startup为1则DispatcherServlet的实例化和初始化会在Web容器启动时候进行.DispatcherServlet初始化会调用init()方法

public final void init() throws ServletException {
if(this.logger.isDebugEnabled()) {
this.logger.debug("Initializing servlet \'" + this.getServletName() + "\'");
}

HttpServletBean.ServletConfigPropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
if(!pvs.isEmpty()) {
try {
BeanWrapper ex = PropertyAccessorFactory.forBeanPropertyAccess(this);
ServletContextResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
ex.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
this.initBeanWrapper(ex);
ex.setPropertyValues(pvs, true);
} catch (BeansException var4) {
if(this.logger.isErrorEnabled()) {
this.logger.error("Failed to set bean properties on servlet \'" + this.getServletName() + "\'", var4);
}

throw var4;
}
}

this.initServletBean();
if(this.logger.isDebugEnabled()) {
this.logger.debug("Servlet \'" + this.getServletName() + "\' configured successfully");
}

}

DispatcherServlet的初始化主要是将当前的servlet类型的实例转换成BeanWrapper类型的实例,并使用Spring提供的注入功能进行相应属性的注入.同时对servletBean进行初始化.

  • initServletBean()方法主要是调用initWebApplication()方法对ContextLoadListener创建的ApplicationContext上下文环境进行进一步的补充.
protected final void initServletBean() throws ServletException {
this.getServletContext().log("Initializing Spring FrameworkServlet \'" + this.getServletName() + "\'");
if(this.logger.isInfoEnabled()) {
this.logger.info("FrameworkServlet \'" + this.getServletName() + "\': initialization started");
}

long startTime = System.currentTimeMillis();

try {
this.webApplicatiOnContext= this.initWebApplicationContext();
this.initFrameworkServlet();
} catch (ServletException var5) {
this.logger.error("Context initialization failed", var5);
throw var5;
} catch (RuntimeException var6) {
this.logger.error("Context initialization failed", var6);
throw var6;
}

if(this.logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
this.logger.info("FrameworkServlet \'" + this.getServletName() + "\': initialization completed in " + elapsedTime + " ms");
}

}
  • initWebApplicationContext()方法主要是创建或刷新WebApplicationContext实例并对servlet功能所使用的变量进行初始化

    • 判断创建DispatcherServlet时候是否通过构造器传入了创建好的WebApplicationContext实例,默认构造器未传入

    • 判断servletContext中是否存在已经创建好的WebApplicationContext实例,一般是由ServletContextListener创建并放入servletContext中.

    • 如果以上两种都没有找到创建好的WebApplicationContext实例,则从头创建并进行初始化

    • 调用initStrategies()方法对servlet功能所使用的变量进行初始化

protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootCOntext= WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
WebApplicationContext wac = null;
if(this.webApplicationContext != null) {
wac = this.webApplicationContext;
if(wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext attrName = (ConfigurableWebApplicationContext)wac;
if(!attrName.isActive()) {
if(attrName.getParent() == null) {
attrName.setParent(rootContext);
}

this.configureAndRefreshWebApplicationContext(attrName);
}
}
}

if(wac == null) {
wac = this.findWebApplicationContext();
}

if(wac == null) {
wac = this.createWebApplicationContext(rootContext);
}

if(!this.refreshEventReceived) {
this.onRefresh(wac);
}

if(this.publishContext) {
String attrName1 = this.getServletContextAttributeName();
this.getServletContext().setAttribute(attrName1, wac);
if(this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet \'" + this.getServletName() + "\' as ServletContext attribute with name [" + attrName1 + "]");
}
}

return wac;
}
  • 调用initStrategies()方法对servlet功能所使用的变量进行初始化,这个函数才是SpringMVC核心逻辑的初始化所在
protected void initStrategies(ApplicationContext context) {
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
this.initHandlerMappings(context);
this.initHandlerAdapters(context);
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
this.initViewResolvers(context);
this.initFlashMapManager(context);
}

(4) 结论

SpringMVC的初始化主要包括两部分:ServletContextListener监听器初始化WebApplicationContext将Spring与Web应用结合起来,DispatcherServlet初始化判断是否WebApplicationContext已经被创建如果没有则重新创建,如果有则进行相应的属性注入,同时也会对servlet功能所使用的变量进行初始化.


推荐阅读
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 解决java.lang.IllegalStateException: ApplicationEventMulticaster not initialized错误的方法和原因
    本文介绍了解决java.lang.IllegalStateException: ApplicationEventMulticaster not initialized错误的方法和原因。其中包括修改包名、解决service name重复、处理jar包冲突和添加maven依赖等解决方案。同时推荐了一个人工智能学习网站,该网站内容通俗易懂,风趣幽默,值得一看。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • javascript  – 概述在Firefox上无法正常工作
    我试图提出一些自定义大纲,以达到一些Web可访问性建议.但我不能用Firefox制作.这就是它在Chrome上的外观:而那个图标实际上是一个锚点.在Firefox上,它只概述了整个 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 标题: ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • SpringBoot整合SpringSecurity+JWT实现单点登录
    SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ... [详细]
author-avatar
斗就斗D_994
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有