springmvc Web上下文初始化
Web上下文初始化
web上下文与SerlvetContext的生命周期应该是相同的,springmvc中的web上下文初始化是由ContextLoaderListener来启动的
在web.xml中配置ContextLoaderListener
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
ContextLoaderListener
ContextLoaderListener实现了ServletContextListener接口,ServletContextListener是Servlet定义的,提供了与Servlet生命周期结合的回调,contextInitialized方法和contextDestroyed方法;ContextLoaderListener继承了ContextLoader类,通过ContextLoader来完成实际的WebApplicationContext的初始化工作,并将WebApplicationContext存放至ServletContext中,ContextLoader就像是spring应用在web容器中的启动器
从spring3.x起就不需要配置监听器ContextLoaderListener,只需要配置DispatcherServlet就可以了,只是没有父容器了而已,只读取mvc配置文件。如果想要spring父容器时,才需要配置ContextLoaderListener
可参考文章 spring与springmvc整合
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
/**
* Initialize the root web application context.
*/
// ServletContext被创建时触发,初始化web上下文
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
/**
* Close the root web application context.
*/
// ServletContext被销毁时触发,关闭web上下文
@Override
public void contextDestroyed(ServletContextEvent event) {
closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}
在启动时会创建一个WebApplicationContext作为IOC容器,默认的实现类是XmlWebApplicationContext
/** Default config location for the root context */
// 默认的配置位置,如果不进行配置,就会读取这个文件
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";
/** Default prefix for building a config location for a namespace */
// 配置文件默认在/WEB-INF/目录下
public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
/** Default suffix for building a config location for a namespace */
// 配置文件默认后缀名是.xml
public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";
initWebApplicationContext初始化
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
// WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE是WebApplicationContext.class.getName() + ".ROOT"
// 如果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!");
}
Log logger = LogFactory.getLog(ContextLoader.class);
servletContext.log("Initializing Spring root WebApplicationContext");
long startTime = System.currentTimeMillis();
try {
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
if (this.context == null) {
// 初始化context
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);
}
}
// 记录在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) {
currentContextPerThread.put(ccl, this.context);
}
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;
}
}
创建WebApplicationContext上下文
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
// 如果在web.xml中有配置contextClass,则使用配置的类
// 如果没有配置,则使用默认的配置 ContextLoader.properties
// org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
Class<?> contextClass = determineContextClass(sc);
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
}
return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
}
servlet3.0规范
servlet3.0后支持不使用web.xml的方式配置。
在spring-web中services下配置有javax.servlet.ServletContainerInitializer文件,其内容为org.springframework.web.SpringServletContainerInitializer,找到该类发现Servlet容器(例如tomcat)启动时,会将SPI注册的Java EE接口ServletContainerInitializer的所有的实现类(例如,SpringServletContainerInitializer)挨个回调其onStartup方法。
而onStartup方法是需要参数的,这时@HandlesTypes就派上用场了。onStartup方法所需要的参数就通过@HandlesTypes注解传入
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer
该类会调用所有WebApplicationInitializer的onStartup方法
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
找到WebApplicationInitializer的子类AbstractAnnotationConfigDispatcherServletInitializer,我们需要继承AbstractAnnotationConfigDispatcherServletInitializer实现其三个抽象方法
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
/*
* 获取根容器的配置类,该配置类就类似于我们以前经常写的Spring的配置文件,然后创建出一个父容器
* 带有@Configuration注解的类用来配置ContextLoaderListener
*/
@Override
protected Class<?>[] getRootConfigClasses() {
// TODO Auto-generated method stub
return null;
}
/*
* 获取web容器的配置类,该配置类就类似于我们以前经常写的Spring MVC的配置文件,然后创建出一个子容器
* 带有@Configuration注解的类用来配置DispatcherServlet
*/
@Override
protected Class<?>[] getServletConfigClasses() {
// TODO Auto-generated method stub
return null;
}
// 获取DispatcherServlet的映射信息
@Override
protected String[] getServletMappings() {
// TODO Auto-generated method stub
return new String[]{"/"};
}
}
这样我们就不需要配置web.xml配置文件了,其会同时创建DispatcherServlet和ContextLoaderListener
https://zhhll.icu/2020/框架/springmvc/底层剖析/0.Web上下文初始化/
本文由 mdnice 多平台发布
相关文章:
springmvc Web上下文初始化
Web上下文初始化 web上下文与SerlvetContext的生命周期应该是相同的,springmvc中的web上下文初始化是由ContextLoaderListener来启动的 web上下文初始化流程 在web.xml中配置ContextLoaderListener <listener> <listener-class>org.springframework.…...
Verilog实战学习到RiscV - 2 : wire 和 reg 的区别
Verilog: wire 和 reg 的区别 1 引言 看Verilog例子过程中,总是分不清 wire 和 reg 的区别。这篇文章把两者放在一起总结一下,并且对比何时使用它们。 1.1 wire :组合逻辑 wire 是 Verilog 设计中的简单导线(或任意宽度的总线…...
OpenGL给定直线起点和终点不同的颜色,使用中点Bresenham画线
用鼠标左键按下确定直线起点,鼠标左键抬起确定直线终点。放一部分代码。 // 中点Bresenham算法.cpp : 定义控制台应用程序的入口点。 //#include "stdafx.h" #include <GL/glut.h> #include <iostream> #include <cmath>int windowWidt…...
IT行业的现状与未来发展趋势:从云计算到量子计算的技术变革
随着技术的不断进步,IT行业已经成为推动全球经济和社会发展的关键力量。从云计算、大数据、人工智能到物联网、5G通信和区块链,这些技术正在重塑我们的生活和工作方式。本文将深入探讨当前IT行业的现状,并展望未来发展趋势,旨在为…...
电脑远程控制另一台电脑怎么弄?
可以远程控制另一台电脑吗? “你好,我对远程访问技术不太了解。现在,我希望我的朋友可以远程控制我的Windows 10电脑,以便她能帮我解决一些问题。请问,有没有免费的方法可以实现这种远程控制?我该如何操作…...
软件设计师备考 | 案例专题之面向对象设计 概念与例题
相关概念 关系 依赖:一个事物的语义依赖于另一个事物的语义的变化而变化 关联:一种结构关系,描述了一组链,链是对象之间的连接。分为组合和聚合,都是部分和整体的关系,其中组合事物之间关系更强。两个类之…...
UniApp 2.0可视化开发工具:引领前端开发新纪元
一、引言 在移动互联网迅猛发展的今天,移动应用开发已经成为前端开发的重要方向之一。为了简化移动应用开发流程,提高开发效率,各大开发平台不断推出新的工具和框架。UniApp作为一款跨平台的移动应用开发框架,自诞生以来就备受开…...
前端调用浏览器录音功能且生成文件(vue)
如果可以实现记得点赞分享,谢谢老铁~ 首先在页面中给两个按钮,分别是“开始录音”,“结束录音”。以及录音成功后生成一个下载语音的链接。 1. 先看页面展示 <template><div><button click"startRecording…...
「大数据」Kappa架构
Kappa架构是一种处理大数据的架构,它作为Lambda架构的替代方案出现。Kappa架构的核心思想是简化数据处理流程,通过使用单一的流处理层来同时处理实时和批量数据,从而避免了Lambda架构中需要维护两套系统(批处理层和速度层…...
详细分析Element Plus中的ElMessageBox弹窗用法(附Demo及模版)
目录 前言1. 基本知识2. Demo3. 实战4. 模版 前言 由于需要在登录时,附上一些用户说明书的弹窗 对于ElMessageBox的基本知识详细了解 可通过官网了解基本的语法知识ElMessageBox官网基本知识 1. 基本知识 Element Plus 是一个基于 Vue 3 的组件库,其中…...
Python自动化工具(桌面自动化、Web自动化、游戏辅助)
工具介绍 连点工具是一款可以模拟键鼠后台操作的连点器工具。支持鼠标连点、键鼠脚本录制,支持辅助您实现办公自动化以及辅助游戏操作。功能简洁易用,非常方便操作。连点工具让您在在玩游戏、网购抢购的时候全自动点击鼠标!主要功能有&#…...
opencv进阶 ——(五)图像处理之马赛克
一、遍历图像并对每个马赛克区域进行像素化处理 for (int y 0; y < image.rows; y blockSize) {for (int x 0; x < image.cols; x blockSize) {cv::Rect rect cv::Rect(x, y, std::min(blockSize, image.cols - x), std::min(blockSize, image.rows - y));cv::Scal…...
电机控制系列模块解析(22)—— 零矢量刹车
一、零矢量刹车 基本概念 逆变器通常采用三相桥式结构,包含六个功率开关元件(如IGBT或MOSFET),分为上桥臂和下桥臂。每个桥臂由两个反并联的开关元件组成,上桥臂和下桥臂对应于电机三相绕组的正负端。正常工作时&…...
自定义一个SpringBoot场景启动器
前言 一个刚刚看完SpringBoot自动装配原理的萌新依据自己的理解写下的文章,如有大神发现错误,敬请斧正,不胜感激。 分析SpringBoot自动配置原理 SpringBoot的启动从被SpringBootApplication修饰的启动类开始,SpringBootApplicaiotn注解中最…...
UDP的报文结构和注意事项
UDP协议是在传输层的协议。 UDP无连接,不可靠传输,面向数据报,全双工。 UDP的报文结构 学习网络协议,最主要的就是报文格式。 对于UDP来说,应用层的数据到达,UDP之后,就会给应用层的数据报前面…...
rust语言一些规则学习
目录 rust中迭代器的使用(iter().map()与for循环的区别)map()与for的描述区别总结 最后更新时间2024-05-24 rust中迭代器的使用(iter().map()与for循环的区别) map()与for的描述 rust源码中关于iter().map()函数的解释ÿ…...
QML基本语法介绍
为什么使用QML 开发者效率 将前后端分离,QML和JavaScript语言主要用于前度UI的方法,后端有C++来完成绘制。将JavaScript和C++分开能够快速迭代开发; 跨平台移植性 基于Qt平台的统一抽象概念,现在可以更加容易和快速和将Qt移植到更多的平台上。 开发的开放 Qt是由Qt-Proje…...
学习和分享关于 Vue.js 的路由(vue-router)
学习和分享关于 Vue.js 的路由(vue-router)是一个非常有价值的主题,因为路由是构建单页应用程序(SPA)的核心部分。本文将介绍 Vue.js 路由的基本概念和实现,并展示一个典型的项目目录结构。 目录 Vue.js 路…...
小猪APP分发:一站式免费应用推广解决方案
在竞争激烈的移动应用市场中,寻找一个高效且成本友好的方式来推广自己的应用程序,成为了众多开发者面临的共同挑战。幸运的是,像"小猪APP分发www.appzhu.cn"这样的平台应运而生,为开发者提供了一个全面、免费的应用分发…...
新抖:抖音的数据分析平台,敢用深色系,别的真不敢!
举报 评论 0...
今天不设计灰度策略,明天就回滚AI版本:AI原生研发最后的防御工事——4层熔断+2级回滚+1键快照应急协议
第一章:今天不设计灰度策略,明天就回滚AI版本:AI原生研发最后的防御工事——4层熔断2级回滚1键快照应急协议 2026奇点智能技术大会(https://ml-summit.org) 在AI模型服务化(MaaS)生产环境中,单次错误推理可…...
OpenMV+STM32串口通信避坑指南:从数据打包到LCD显示的完整流程(附源码)
OpenMV与STM32串口通信实战:从数据帧设计到LCD显示的避坑全攻略 引言 当你第一次尝试将OpenMV的识别结果通过串口传输到STM32并在LCD上显示时,大概率会遇到数据丢包、解析错误或显示异常等问题。这不是你的代码写得不够好,而是串口通信本身就…...
Illustrator脚本终极指南:5个核心脚本彻底改变你的设计工作流
Illustrator脚本终极指南:5个核心脚本彻底改变你的设计工作流 【免费下载链接】illustrator-scripts Adobe Illustrator scripts 项目地址: https://gitcode.com/gh_mirrors/il/illustrator-scripts Adobe Illustrator是设计师的必备工具,但繁琐的…...
波普尔:反教皇的“新教皇”——一场百年认知诈骗的终极揭露
波普尔:反教皇的“新教皇”——一场百年认知诈骗的终极揭露摘要波普尔以“反教皇”自居,实则上演了最隐蔽的学术独裁。他通过偷换“绝对真理”概念,将确定性真理污名化为教皇式专制,再借“可证伪性”自封科学裁判,垄断…...
数据摄取构建模块简介(预览版)(一)刺
一、语言特性:Java 26 与模式匹配进化 1.1 Java 26 语言级别支持 IDEA 2026.1 EAP 最引人注目的变化之一,就是新增 Java 26 语言级别支持。这意味着开发者可以提前体验和测试即将在 JDK 26 中正式发布的语言特性。 其中最重要的变化是对 JEP 530 的全面支…...
Hyper-V直通M.2 NVMe硬盘前,你必须搞清楚的3个关键点和1个误区
Hyper-V直通M.2 NVMe硬盘前必须掌握的3个技术真相与1个常见误判 当你盯着那块标称读写速度3500MB/s的M.2 NVMe硬盘,盘算着如何让它为虚拟机提供原生级性能时,90%的技术决策失误往往发生在点击"直通"按钮之前。这不是关于操作步骤的教程&#x…...
5分钟搭建Vue3管理后台:开源免费的企业级解决方案终极指南
5分钟搭建Vue3管理后台:开源免费的企业级解决方案终极指南 【免费下载链接】vue-pure-admin 全面ESMVue3ViteElement-PlusTypeScript编写的一款后台管理系统(兼容移动端) 项目地址: https://gitcode.com/GitHub_Trending/vu/vue-pure-admin…...
LinkSwift:八大网盘直链解析工具,告别下载限速的终极方案
LinkSwift:八大网盘直链解析工具,告别下载限速的终极方案 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移…...
Lumafly:空洞骑士模组管理的终极解决方案,一键安装告别复杂配置
Lumafly:空洞骑士模组管理的终极解决方案,一键安装告别复杂配置 【免费下载链接】Lumafly A cross platform mod manager for Hollow Knight written in Avalonia. 项目地址: https://gitcode.com/gh_mirrors/lu/Lumafly Lumafly是一款专为空洞骑…...
如何用Zotero Style插件高效管理文献:从阅读追踪到智能标签的完整攻略
如何用Zotero Style插件高效管理文献:从阅读追踪到智能标签的完整攻略 【免费下载链接】zotero-style Ethereal Style for Zotero 项目地址: https://gitcode.com/GitHub_Trending/zo/zotero-style Zotero Style插件是一款能够彻底改变你文献管理体验的Zoter…...
