1. tomcat的容器层次结构是什么?
答案:
tomcat采用分层的容器架构,每一层都实现了container接口。
容器层次结构:
server (standardserver)
└── service (standardservice)
├── connector (多个)
└── engine (standardengine)
└── host (standardhost - 多个)
└── context (standardcontext - 多个)
└── wrapper (standardwrapper - 多个)各层容器详解:
1. server - 服务器实例
- 实现类:
org.apache.catalina.core.standardserver - 职责:
- 代表整个catalina servlet容器
- 管理全局资源(jndi)
- 监听shutdown端口
- 配置:
<server port="8005" shutdown="shutdown"> ... </server>
2. service - 服务组
- 实现类:
org.apache.catalina.core.standardservice - 职责:
- 将多个connector与一个engine关联
- 允许多个协议共享同一组web应用
- 配置:
<service name="catalina"> <connector ... /> <engine ... /> </service>
3. engine - 引擎
- 实现类:
org.apache.catalina.core.standardengine - 职责:
- 处理所有connector的请求
- 包含多个虚拟主机(host)
- 支持集群和负载均衡
- 配置:
<engine name="catalina" defaulthost="localhost"> ... </engine>
4. host - 虚拟主机
- 实现类:
org.apache.catalina.core.standardhost - 职责:
- 代表一个虚拟主机
- 管理web应用的部署
- 支持域名别名
- 配置:
<host name="localhost" appbase="webapps"
unpackwars="true" autodeploy="true">
...
</host>5. context - web应用
- 实现类:
org.apache.catalina.core.standardcontext - 职责:
- 代表一个web应用(servletcontext)
- 管理servlet、filter、listener
- 处理会话管理
- 管理类加载器
- 配置:
<context path="/myapp" docbase="myapp.war"
reloadable="true">
...
</context>6. wrapper - servlet包装器
- 实现类:
org.apache.catalina.core.standardwrapper - 职责:
- 代表一个servlet定义
- 管理servlet生命周期
- 处理servlet的初始化参数
- 管理servlet实例池(单线程模式)
- 配置: 通过web.xml或注解定义
容器特性:
1. 每个容器都有:
- pipeline (管道)
- valve (阀门)
- lifecycle (生命周期管理)
- loader (类加载器 - context级别)
- manager (会话管理器 - context级别)
- realm (安全域)
2. 请求处理流程:
connector ↓ engine.pipeline → engine.valve ↓ host.pipeline → host.valve ↓ context.pipeline → context.valve ↓ wrapper.pipeline → wrapper.valve ↓ servlet.service()
2. tomcat的生命周期管理机制是什么?
答案:
tomcat使用统一的生命周期管理机制,所有主要组件都实现lifecycle接口。
lifecycle接口
位置: org.apache.catalina.lifecycle
核心方法:
public interface lifecycle {
void init() throws lifecycleexception;
void start() throws lifecycleexception;
void stop() throws lifecycleexception;
void destroy() throws lifecycleexception;
void addlifecyclelistener(lifecyclelistener listener);
void removelifecyclelistener(lifecyclelistener listener);
}
生命周期状态:
new (新建) ↓ init() initializing (初始化中) ↓ initialized (已初始化) ↓ start() starting_prep (启动准备) ↓ starting (启动中) ↓ started (已启动) ↓ stop() stopping_prep (停止准备) ↓ stopping (停止中) ↓ stopped (已停止) ↓ destroy() destroying (销毁中) ↓ destroyed (已销毁)
生命周期事件:
初始化阶段:
before_init_event- 初始化前after_init_event- 初始化后
启动阶段:
before_start_event- 启动前start_event- 启动时after_start_event- 启动后
停止阶段:
before_stop_event- 停止前stop_event- 停止时after_stop_event- 停止后
销毁阶段:
before_destroy_event- 销毁前after_destroy_event- 销毁后
lifecyclebase实现:
位置: org.apache.catalina.util.lifecyclebase
模板方法模式:
public abstract class lifecyclebase implements lifecycle {
@override
public final synchronized void init() throws lifecycleexception {
// 状态检查
if (!state.equals(lifecyclestate.new)) {
invalidtransition(lifecycle.before_init_event);
}
// 触发before_init事件
setstateinternal(lifecyclestate.initializing, null, false);
// 调用子类实现
initinternal();
// 触发after_init事件
setstateinternal(lifecyclestate.initialized, null, false);
}
protected abstract void initinternal() throws lifecycleexception;
protected abstract void startinternal() throws lifecycleexception;
protected abstract void stopinternal() throws lifecycleexception;
protected abstract void destroyinternal() throws lifecycleexception;
}
组件启动顺序:
1. server.init()
└── service.init()
├── engine.init()
│ └── host.init()
│ └── context.init()
│ └── wrapper.init()
└── connector.init()
2. server.start()
└── service.start()
├── engine.start()
│ └── host.start()
│ └── context.start()
│ └── wrapper.start()
└── connector.start()
生命周期监听器:
自定义监听器:
public class mylifecyclelistener implements lifecyclelistener {
@override
public void lifecycleevent(lifecycleevent event) {
if (lifecycle.after_start_event.equals(event.gettype())) {
system.out.println("component started: " + event.getlifecycle());
}
}
}
配置监听器:
<server> <listener classname="com.example.mylifecyclelistener" /> </server>
3. servlet的生命周期在tomcat中是如何管理的?
答案:
servlet的生命周期由wrapper组件管理。
servlet生命周期阶段:
1. 加载和实例化
// standardwrapper.loadservlet()
public synchronized servlet loadservlet() throws servletexception {
// 使用webappclassloader加载servlet类
class<?> clazz = classloader.loadclass(servletclass);
// 实例化servlet
servlet servlet = (servlet) clazz.newinstance();
return servlet;
}
触发时机:
- 第一次请求到达时(懒加载)
- 配置了
load-on-startup时在启动时加载
2. 初始化 (init)
// standardwrapper.initservlet()
private synchronized void initservlet(servlet servlet) throws servletexception {
// 创建servletconfig
servletconfig config = new standardwrapperfacade(this);
// 调用servlet.init()
servlet.init(config);
// 标记为已初始化
singlethreadmodel = servlet instanceof singlethreadmodel;
}
servletconfig提供:
- servlet名称
- servletcontext引用
- 初始化参数
3. 服务 (service)
// standardwrapper.allocate()
public servlet allocate() throws servletexception {
// 单线程模式:从池中获取实例
if (singlethreadmodel) {
return pool.pop();
}
// 多线程模式:返回单例
return instance;
}
// standardwrappervalve.invoke()
public void invoke(request request, response response) {
// 分配servlet实例
servlet servlet = wrapper.allocate();
// 创建请求和响应门面
servletrequest req = request.getrequest();
servletresponse res = response.getresponse();
// 调用servlet.service()
servlet.service(req, res);
// 释放servlet实例
wrapper.deallocate(servlet);
}
4. 销毁 (destroy)
// standardwrapper.unload()
public synchronized void unload() throws servletexception {
// 调用servlet.destroy()
if (instance != null) {
instance.destroy();
instance = null;
}
// 清理单线程模式的实例池
if (singlethreadmodel && pool != null) {
while (!pool.isempty()) {
pool.pop().destroy();
}
}
}
触发时机:
- context停止或重新加载
- tomcat关闭
- servlet被替换
load-on-startup配置:
web.xml:
<servlet>
<servlet-name>initservlet</servlet-name>
<servlet-class>com.example.initservlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>注解:
@webservlet(name = "initservlet",
urlpatterns = "/init",
loadonstartup = 1)
public class initservlet extends httpservlet {
// ...
}
加载顺序:
- 值越小越先加载
- 负数表示懒加载
- 相同值的加载顺序不确定
singlethreadmodel (已废弃):
public class oldservlet extends httpservlet implements singlethreadmodel {
// tomcat会为每个请求创建新实例或使用实例池
}
问题:
- 性能开销大
- 无法保证线程安全(静态变量、外部资源)
- servlet 2.4已废弃
异步servlet:
servlet 3.0+支持:
@webservlet(urlpatterns = "/async", asyncsupported = true)
public class asyncservlet extends httpservlet {
protected void doget(httpservletrequest req, httpservletresponse resp) {
asynccontext asynccontext = req.startasync();
asynccontext.start(() -> {
// 异步处理
asynccontext.complete();
});
}
}
4. tomcat的pipeline和valve机制是什么?
答案:
pipeline-valve是tomcat实现请求处理链的核心机制,类似于责任链模式。
架构设计:
pipeline接口:
public interface pipeline {
valve getbasic();
void setbasic(valve valve);
void addvalve(valve valve);
valve[] getvalves();
void removevalve(valve valve);
valve getfirst();
}
valve接口:
public interface valve {
valve getnext();
void setnext(valve next);
void invoke(request request, response response)
throws ioexception, servletexception;
}
每个容器的pipeline:
engine pipeline: standardenginevalve (basic valve) host pipeline: errorreportvalve → standardhostvalve (basic valve) context pipeline: nonloginauthenticator → standardcontextvalve (basic valve) wrapper pipeline: standardwrappervalve (basic valve)
请求处理流程:
1. connector接收请求 ↓ 2. engine.pipeline.first.invoke() ↓ 3. [自定义valve] → standardenginevalve ↓ (选择host) 4. host.pipeline.first.invoke() ↓ 5. [errorreportvalve] → standardhostvalve ↓ (选择context) 6. context.pipeline.first.invoke() ↓ 7. [authenticatorvalve] → standardcontextvalve ↓ (选择wrapper) 8. wrapper.pipeline.first.invoke() ↓ 9. standardwrappervalve ↓ (调用servlet) 10. servlet.service()
standardenginevalve:
位置: org.apache.catalina.core.standardenginevalve
public void invoke(request request, response response) {
// 获取host
host host = request.gethost();
if (host == null) {
response.senderror(httpservletresponse.sc_bad_request);
return;
}
// 调用host的pipeline
host.getpipeline().getfirst().invoke(request, response);
}
standardhostvalve:
位置: org.apache.catalina.core.standardhostvalve
public void invoke(request request, response response) {
// 获取context
context context = request.getcontext();
if (context == null) {
response.senderror(httpservletresponse.sc_not_found);
return;
}
// 调用context的pipeline
context.getpipeline().getfirst().invoke(request, response);
}
standardcontextvalve:
位置: org.apache.catalina.core.standardcontextvalve
public void invoke(request request, response response) {
// 获取wrapper
wrapper wrapper = request.getwrapper();
if (wrapper == null) {
response.senderror(httpservletresponse.sc_not_found);
return;
}
// 调用wrapper的pipeline
wrapper.getpipeline().getfirst().invoke(request, response);
}
standardwrappervalve:
位置: org.apache.catalina.core.standardwrappervalve
public void invoke(request request, response response) {
// 分配servlet实例
servlet servlet = wrapper.allocate();
// 创建filter链
applicationfilterchain filterchain =
applicationfilterfactory.createfilterchain(request, wrapper, servlet);
// 执行filter链和servlet
filterchain.dofilter(request.getrequest(), response.getresponse());
// 释放servlet实例
wrapper.deallocate(servlet);
}
自定义valve:
实现valve:
public class customvalve extends valvebase {
@override
public void invoke(request request, response response)
throws ioexception, servletexception {
// 前置处理
long starttime = system.currenttimemillis();
// 调用下一个valve
getnext().invoke(request, response);
// 后置处理
long duration = system.currenttimemillis() - starttime;
system.out.println("request took: " + duration + "ms");
}
}
配置valve:
<host name="localhost">
<valve classname="com.example.customvalve" />
</host>常用内置valve:
1. accesslogvalve - 访问日志
<valve classname="org.apache.catalina.valves.accesslogvalve"
directory="logs"
prefix="localhost_access_log"
suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />2. remoteaddrvalve - ip过滤
<valve classname="org.apache.catalina.valves.remoteaddrvalve"
allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />3. errorreportvalve - 错误报告
<valve classname="org.apache.catalina.valves.errorreportvalve"
showreport="false"
showserverinfo="false" />4. rewritevalve - url重写
<valve classname="org.apache.catalina.valves.rewrite.rewritevalve" />
5. tomcat的类加载机制是什么?
答案:
tomcat使用自定义的类加载器层次结构,实现应用隔离和热部署。
类加载器层次:
bootstrap classloader (jvm)
↓
system classloader (jvm)
↓
common classloader ($catalina_home/lib)
↓
├── server classloader (server classes - 已移除)
└── shared classloader (shared classes - 可选)
↓
webappclassloader (/web-inf/classes, /web-inf/lib)
↓
jsp classloader (jsp编译后的类)webappclassloader:
位置: org.apache.catalina.loader.webappclassloaderbase
特点:
- 每个web应用有独立的类加载器
- 实现应用隔离
- 支持热部署
加载顺序 (默认):
- bootstrap和system类加载器 (java核心类)
- /web-inf/classes (应用类)
- /web-inf/lib/*.jar (应用库)
- common classloader (tomcat共享库)
委托模式:
默认情况下,webappclassloader打破了双亲委派模型:
public class<?> loadclass(string name) throws classnotfoundexception {
// 1. 检查是否已加载
class<?> clazz = findloadedclass(name);
if (clazz != null) {
return clazz;
}
// 2. 系统类委托给父加载器
if (name.startswith("java.")) {
return parent.loadclass(name);
}
// 3. 尝试自己加载 (打破双亲委派)
try {
clazz = findclass(name);
if (clazz != null) {
return clazz;
}
} catch (classnotfoundexception e) {
// 继续
}
// 4. 委托给父加载器
return parent.loadclass(name);
}
配置委托模式:
<context path="/myapp" docbase="myapp.war">
<loader delegate="true"/>
</context>delegate="false"(默认): 先自己加载,再委托父加载器delegate="true": 先委托父加载器,再自己加载(标准双亲委派)
类加载路径:
common classloader加载:
$catalina_home/lib$catalina_base/lib
webappclassloader加载:
/web-inf/classes/web-inf/lib/*.jar
热部署实现:
context配置:
<context path="/myapp" docbase="myapp.war" reloadable="true">
<watchedresource>web-inf/web.xml</watchedresource>
<watchedresource>web-inf/classes</watchedresource>
</context>工作原理:
- containerbackgroundprocessor 定期检查
- 检测到类文件变化
- 调用
context.reload() - 停止context
- 销毁旧的webappclassloader
- 创建新的webappclassloader
- 重新加载所有类
- 启动context
代码实现:
// standardcontext.backgroundprocess()
public void backgroundprocess() {
if (reloadable && modified()) {
reload();
}
}
// standardcontext.reload()
public synchronized void reload() {
// 停止context
stop();
// 启动context (会创建新的classloader)
start();
}
parallelwebappclassloader:
位置: org.apache.catalina.loader.parallelwebappclassloader
特点:
- 支持并行类加载 (java 7+)
- 提高多线程环境下的加载性能
- 避免死锁
配置:
<context>
<loader loaderclass="org.apache.catalina.loader.parallelwebappclassloader"/>
</context>类加载问题排查:
1. classnotfoundexception
- 检查类是否在正确的路径
- 检查jar文件是否损坏
- 检查类加载器委托配置
2. noclassdeffounderror
- 类的依赖类找不到
- 静态初始化失败
3. classcastexception
- 同一个类被不同类加载器加载
- 检查是否有重复的jar
4. linkageerror
- 类被多次加载
- 检查common和webapp路径中的重复jar
6. tomcat的会话管理机制是什么?
答案:
tomcat通过manager组件管理http会话。
manager接口:
位置: org.apache.catalina.manager
核心方法:
public interface manager {
session createsession(string sessionid);
session findsession(string id) throws ioexception;
void remove(session session);
void add(session session);
session[] findsessions();
void load() throws ioexception;
void unload() throws ioexception;
}
manager实现类:
1. standardmanager (默认)
特点:
- 会话存储在内存中
- 支持会话持久化到文件
- 单机部署
配置:
<context>
<manager classname="org.apache.catalina.session.standardmanager"
maxactivesessions="1000"
sessionidlength="16" />
</context>持久化:
- tomcat正常关闭时,会话序列化到
sessions.ser - 启动时从文件恢复会话
2. persistentmanager
特点:
- 支持会话持久化到store
- 支持会话钝化(passivation)
- 节省内存
配置:
<context>
<manager classname="org.apache.catalina.session.persistentmanager"
maxactivesessions="1000"
minidleswap="5"
maxidleswap="10"
maxidlebackup="2">
<store classname="org.apache.catalina.session.filestore"
directory="sessions"/>
</manager>
</context>参数说明:
minidleswap: 会话空闲多久后钝化到storemaxidleswap: 会话空闲多久后必须钝化maxidlebackup: 会话空闲多久后备份到store
3. deltamanager (集群)
特点:
- 会话复制到集群所有节点
- 适合小集群(< 4节点)
- 全量复制
配置:
<cluster classname="org.apache.catalina.ha.tcp.simpletcpcluster">
<manager classname="org.apache.catalina.ha.session.deltamanager"
expiresessionsonshutdown="false"
notifylistenersonreplication="true"/>
</cluster>4. backupmanager (集群)
特点:
- 会话只复制到一个备份节点
- 适合大集群
- 节省网络带宽
配置:
<cluster classname="org.apache.catalina.ha.tcp.simpletcpcluster">
<manager classname="org.apache.catalina.ha.session.backupmanager"
mapsendoptions="6"/>
</cluster>session实现:
standardsession:
public class standardsession implements httpsession, session, serializable {
protected string id; // 会话id
protected long creationtime; // 创建时间
protected long lastaccessedtime; // 最后访问时间
protected int maxinactiveinterval; // 最大不活动时间
protected map<string, object> attributes; // 会话属性
protected boolean isvalid; // 是否有效
protected manager manager; // 所属manager
}
会话id生成:
sessionidgenerator:
// org.apache.catalina.util.standardsessionidgenerator
public string generatesessionid() {
byte[] random = new byte[16];
securerandom.nextbytes(random);
return tohexstring(random);
}
配置:
<manager sessionidlength="32">
<sessionidgenerator classname="org.apache.catalina.util.standardsessionidgenerator"
sessionidlength="32"/>
</manager>会话超时:
配置超时时间:
web.xml:
<session-config>
<session-timeout>30</session-timeout> <!-- 分钟 -->
</session-config>context.xml:
<context sessiontimeout="30"/>
程序设置:
session.setmaxinactiveinterval(1800); // 秒
超时检查:
// standardmanager.backgroundprocess()
public void backgroundprocess() {
session[] sessions = findsessions();
for (session session : sessions) {
if (session.isvalid() && session.isexpired()) {
session.expire();
}
}
}
会话监听器:
httpsessionlistener:
@weblistener
public class sessionlistener implements httpsessionlistener {
@override
public void sessioncreated(httpsessionevent se) {
system.out.println("session created: " + se.getsession().getid());
}
@override
public void sessiondestroyed(httpsessionevent se) {
system.out.println("session destroyed: " + se.getsession().getid());
}
}
httpsessionattributelistener:
@weblistener
public class sessionattributelistener implements httpsessionattributelistener {
@override
public void attributeadded(httpsessionbindingevent se) {
system.out.println("attribute added: " + se.getname());
}
@override
public void attributeremoved(httpsessionbindingevent se) {
system.out.println("attribute removed: " + se.getname());
}
@override
public void attributereplaced(httpsessionbindingevent se) {
system.out.println("attribute replaced: " + se.getname());
}
}
cookie配置:
context.xml:
<context>
<cookieprocessor classname="org.apache.tomcat.util.http.rfc6265cookieprocessor"
samesitecookies="strict"/>
</context>web.xml:
<session-config>
<cookie-config>
<name>mysessionid</name>
<domain>.example.com</domain>
<path>/</path>
<http-only>true</http-only>
<secure>true</secure>
<max-age>3600</max-age>
</cookie-config>
</session-config>总结
到此这篇关于tomcat servlet容器与生命周期管理面试题及答案的文章就介绍到这了,更多相关tomcat servlet容器与生命周期管理内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论