【Tomcat源码学习】-3.应用管理
2024-10-09 20:34:07
通过上一节我们完成了对容器进行了加载、初始化、启动,而对于应用的加载部分独立出来,本节进行单独的讲解
一、应用加载流程
1)应用识别,Context创建
- 在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容器中
至此,host下面的context,wrapper,等容器就就已经生成并初始化了。
最新文章
- 【前端性能】高性能滚动 scroll 及页面渲染优化
- 跟着百度学PHP[4]OOP面对对象编程-12-抽象类
- 去掉hive字段中的tab
- org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter与org.apache.struts.dispatcher.FilterDispatcher是什么区别?
- c语言 数组名是常量指针
- javascript优化--06模式(对象)01
- jquery的jquery c.browser msie undefined的问题解决办法
- Tkinter教程之Canvas篇(3)
- C++ 文件读写方案选型
- PIL(Python Image Library)生成验证码
- Oracle DB 自动管理共享内存
- Windows进程
- BZOJ 1416: [NOI2006]神奇的口袋( 高精度 )
- 【Bootstrap】 一些提示信息插件
- Mybatis源码分析之存储过程调用
- Dubbo的异常处理
- JAVA垃圾回收机制概要
- 解决:对COM 组件的调用返回了错误 HRESULT E_FAIL
- 【UOJ244】[UER7]短路
- 机器学习中的范数规则化之 L0、L1与L2范数、核范数与规则项参数选择
热门文章
- 使用moy快速开发后台管理系统(一)
- 简单聊聊HTTP/TCP/IP协议
- 深入理解 JavaScript 异步系列(2)—— jquery的解决方案
- 本人开发的JavaWeb急速框架Blast上线了
- 1688: [Usaco2005 Open]Disease Manangement 疾病管理
- SQL-with as基本用法(源码DEMO)
- Xamarin自定义布局系列——ListView的一个自定义实现ItemsControl(横向列表)
- RSA密码体制
- QQ好友在线/离线,怎么测试?
- 获取 metadata 的完整例子 - 每天5分钟玩转 OpenStack(166)