【Tomcat源码学习】-3.应用管理
一、应用加载流程

- 在Host启动后,会调用Host的监听HostConfig进行启动事件处理
- HostConfig在监听到启动事件后,会分别尝试从context.xml下,wabapps下war,webapp下文件夹进行应用的读取,读取过程中通过Host的启停线程池(startStopExecutor)进行独立线程读取,读取最终结果生成Context对象并添加进入Host容器中。注意这里用到了Future<?>协同方式
- 这里构建的Context仅包含如下基本参数(如:name,path,webappVersion,docBase),另外会给Context默认增加监听ContextConfig
2)应用加载,Context启动

- Engine启动ContainerBackgroundProcessor线程进行对所有容器进行后台处理,即调用所有容器的backgroundProcess()方法
- 容器backgroundProcess()方法处理完成后,通知相应的监听器(事件类型为Lifecycle.PERIODIC_EVENT)
- HostConfig会根据Context是否启动,进行相应启动操作(context.start()),
- Context启动过程如下:
- 获取一个WebAppLoader,
- 应用类加载,执行WebAppLoader.start()方法,该方法内,会创建一个ClassLoader(WebappClassLoader),在调用ClassLoader.start()方法进行jar与class的加载
- 添加应用级监听器至Context成员变量中,其中主要有:ServletContextAttributeListener,ServletRequestAttributeListener,ServletRequestListener,HttpSessionIdListener,HttpSessionAttributeListener,ServletContextListener,Context成员变量声明如下:
private List<Object> applicationEventListenersList = new CopyOnWriteArrayList<>(); - 执行SevletContextListener监听器上下文完成初始化方法(注意,Spring就是这里进行的初始化的)
- Context启动完成后,通知相应的监听器ContextConfig,进行启动完成处理
- ContextConfig.start()方法(核心为调用webConfig()方法)
- 读取/WEB-INF/web.xml文件,构建WebXml对象
- 解析所有class,判断是否有使用servlet相关注解(Ljavax/servlet/annotation/WebServlet),如果使用就注解对象手动添加至WebXml对象中,即生成ServletDef定义文件
- 将jsp转换为ServletDef定义文件,并添加至WebXml对象中
将WebXml对象内容解析至Context对象中(方法:configcontext),一个Servlet对应一个Wrapper容器
for (Entry<String, String> entry : webxml.getContextParams().entrySet()) {
context.addParameter(entry.getKey(), entry.getValue());
}//context全局参数
....
for (ErrorPage errorPage : webxml.getErrorPages().values()) {
context.addErrorPage(errorPage);
}//404页面
for (FilterDef filter : webxml.getFilters().values()) {
if (filter.getAsyncSupported() == null) {
filter.setAsyncSupported("false");
}
context.addFilterDef(filter);
}//拦截器
for (FilterMap filterMap : webxml.getFilterMappings()) {
context.addFilterMap(filterMap);
}//拦截器Map
context.setJspConfigDescriptor(webxml.getJspConfigDescriptor());
for (String listener : webxml.getListeners()) {
context.addApplicationListener(listener);
}//监听器
......
for (ServletDef servlet : webxml.getServlets().values()) {
Wrapper wrapper = context.createWrapper();//一个servlet对应一个封装器Wrapper
// Description is ignored
// Display name is ignored
// Icons are ignored
// jsp-file gets passed to the JSP Servlet as an init-param
if (servlet.getLoadOnStartup() != null) {
wrapper.setLoadOnStartup(servlet.getLoadOnStartup().intValue());
}
if (servlet.getEnabled() != null) {
wrapper.setEnabled(servlet.getEnabled().booleanValue());
}
wrapper.setName(servlet.getServletName());
Map<String,String> params = servlet.getParameterMap();
for (Entry<String, String> entry : params.entrySet()) {
wrapper.addInitParameter(entry.getKey(), entry.getValue());
}
wrapper.setRunAs(servlet.getRunAs());
Set<SecurityRoleRef> roleRefs = servlet.getSecurityRoleRefs();
for (SecurityRoleRef roleRef : roleRefs) {
wrapper.addSecurityReference(
roleRef.getName(), roleRef.getLink());
}
wrapper.setServletClass(servlet.getServletClass());
MultipartDef multipartdef = servlet.getMultipartDef();
if (multipartdef != null) {
if (multipartdef.getMaxFileSize() != null &&
multipartdef.getMaxRequestSize()!= null &&
multipartdef.getFileSizeThreshold() != null) {
wrapper.setMultipartConfigElement(new MultipartConfigElement(
multipartdef.getLocation(),
Long.parseLong(multipartdef.getMaxFileSize()),
Long.parseLong(multipartdef.getMaxRequestSize()),
Integer.parseInt(
multipartdef.getFileSizeThreshold())));
} else {
wrapper.setMultipartConfigElement(new MultipartConfigElement(
multipartdef.getLocation()));
}
}
if (servlet.getAsyncSupported() != null) {
wrapper.setAsyncSupported(
servlet.getAsyncSupported().booleanValue());
}
wrapper.setOverridable(servlet.isOverridable());
context.addChild(wrapper);
}
for (Entry<String, String> entry :
webxml.getServletMappings().entrySet()) {
context.addServletMapping(entry.getKey(), entry.getValue());
}
//sesseionConfig对象
SessionConfig sessionConfig = webxml.getSessionConfig();
if (sessionConfig != null) {
if (sessionConfig.getSessionTimeout() != null) {
context.setSessionTimeout(
sessionConfig.getSessionTimeout().intValue());
}
SessionCookieConfig scc =
context.getServletContext().getSessionCookieConfig();
scc.setName(sessionConfig.getCookieName());
scc.setDomain(sessionConfig.getCookieDomain());
scc.setPath(sessionConfig.getCookiePath());
scc.setComment(sessionConfig.getCookieComment());
if (sessionConfig.getCookieHttpOnly() != null) {
scc.setHttpOnly(sessionConfig.getCookieHttpOnly().booleanValue());
}
if (sessionConfig.getCookieSecure() != null) {
scc.setSecure(sessionConfig.getCookieSecure().booleanValue());
}
if (sessionConfig.getCookieMaxAge() != null) {
scc.setMaxAge(sessionConfig.getCookieMaxAge().intValue());
}
if (sessionConfig.getSessionTrackingModes().size() > 0) {
context.getServletContext().setSessionTrackingModes(
sessionConfig.getSessionTrackingModes());
}
}
- 从WebApp加载中读取ServletContainerInitializer的实现,并添加至context容器中
【Tomcat源码学习】-3.应用管理的更多相关文章
- Tomcat源码学习(1)
Tomcat源码学习(1) IntelliJ IDEA 17.3.3 导入 Tomcat 9.0.6源码 下载源码 tomcat_9.0.6 启动 IDEA. 点击 Open,选择刚才下载的文件解压后 ...
- Tomcat源码学习
Tomcat源码学习(一) 转自:http://carllgc.blog.ccidnet.com/blog-htm-do-showone-uid-4092-type-blog-itemid-26309 ...
- 【Tomcat源码学习】-1.概述
Tomcat是用java语言开发的一个Web服务器,最近花了差不多两周时间对Tomcat 9.0源码进行了一遍学习,由于知识储备有限,也只是理解了一个大概,下面就由我来给大家分享一下我对Tomcat的 ...
- Tomcat源码学习 - 环境搭建
一. 源码下载 PS: 多图预警 在开始阅读源码之前,我们需要先构建一个环境,这样才能便于我们对源码进行调试,具体源码我们可以到官网进行下载(这里我以8.5.63版本为例). 二. 项目导入 下载并解 ...
- Tomcat源码学习记录--web服务器初步认识
Tomcat作为开源的轻量级WEB服务器,虽然不是很适合某些大型项目,但是它开源,读其源代码可以很好的提高我们的编程功底和设计思维.Tomcat中用到了很多比较好的设计模式,其中代码风格也很值得我们去 ...
- TOMCAT源码分析——生命周期管理
前言 从server.xml文件解析出来的各个对象都是容器,比如:Server.Service.Connector等.这些容器都具有新建.初始化完成.启动.停止.失败.销毁等状态.tomcat的实现提 ...
- Tomcat源码学习一
这段时间工作不太忙,所以抽时间学习了TOMCAT, TOMCAT实际就是负责保持TCP连接传递到部署的项目中.浏览器实质就是TCP发送器.将用户的请求封装成TCP发送请求.当然格式是双方协定的.使用的 ...
- Mybatis源码学习之事务管理(八)
简述 在实际开发中,数据库事务的控制是一件非常重要的工作,本文将学习Mybatis对事务的管理机制.在Mybatis中基于接口 Transaction 将事务分为两种,一种是JdbcTransacti ...
- Python 源码学习之内存管理 -- (转)
Python 的内存管理架构(Objects/obmalloc.c): _____ ______ ______ ________ [ int ] [ dict ] [ list ] ... [ str ...
- 【Tomcat源码学习】-2.容器管理
Tomcat作为应用服务器,我们可以理解Tomcat本身就是一个容器,用于装载应用,而作为容器本身是由若干组件以及事件构成,容器管理即为管理容器的有机组成部分. 一.Tomcat整体结构: Ser ...
随机推荐
- Asp.Net 常用工具类之Office—Excel导入(5)
之前在做一个项目的时候,客户方面只提供了一份简单的Excel文件,且要跟现有数据进行对接. 当时想到的是如果数据量不大,可以Excel一条一条加进去,无奈数据有几十兆!!! 换了一种思维,进行了导入: ...
- 黑苹果引导工具 Clover 配置详解及Clover Configurator使用
黑苹果引导工具 Clover 配置详解及Clover Configurator使用 2017-03-11 14:01:40 by SemiconductorKING 转自:@三个表哥 简介: 可 ...
- wemall doraemon中Android app商城系统工具集合类,包含各种程序中用到的静态方法
wemall doraemon中Android app商城系统工具集合类,包含各种程序中用到的静态方法,可用于其他商城或者系统的编程参考 package cn.zzu.edu.wemall.utils ...
- 1441: Min
1441: Min Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 320 Solved: 213[Submit][Status][Discuss] De ...
- linux apache添加多站点配置(Ubuntn和Centos)
Linux Apache 多站点配置 Centos 配置方式: 找到 /etc/httpd/conf/http.conf 添加监听端口,eg: Listen 89 虚拟机配置,一个端口对应一个 &l ...
- Struts1.x 环境搭建和技术准备(上)
Struts 1.x 基于 Servlet,Struts 2.x基于Filter 1.servlet的注解配置方式和web.xml配置方式 使用servelt 3.0,eclipse在创建seb项目是 ...
- 分离数据库时出错:无法对数据库'XXX' 执行删除,因为它正用于复制"的解决方法
出现的原因是要分离的数据库是一个发布订阅的数据库.因为正在复制,所以无法脱机. 解决办法是停止发布订阅,或者删掉它..再分离.有部分情况是在复制目录下并没有看到发布订阅. 有可能是因为以前建立发布订阅 ...
- 浩哥解析MyBatis源码(一)——执行流程
原创作品,可以转载,但是请标注出处地址: 一.MyBatis简介 MyBatis框架是一种轻量级的ORM框架,当下十分流行,配合Spring+Spring MVC组成SSM框架,能够胜任几乎所有的项目 ...
- css3特效
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title> ...
- LeetCode -- Word Break 动态规划,详细理解
Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separa ...