2.Tomcat启动阶段
- daemon.start(),tomcat的启动阶段分析
# 1.Bootstrap的start()方法
public void start()
throws Exception {
if( catalinaDaemon==null ) init();
//实际上是执行了catalina的start()方法
Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
method.invoke(catalinaDaemon, (Object [])null);
}
# 1.Catalina的start()方法
public void start() {
if (getServer() == null) {
load();
}
if (getServer() == null) {
log.fatal("Cannot start server. Server instance is not configured.");
return;
}
long t1 = System.nanoTime();
// Start the new server
try {
//启动Server(重点)
getServer().start();
} catch (LifecycleException e) {
log.fatal(sm.getString("catalina.serverStartFail"), e);
try {
getServer().destroy();
} catch (LifecycleException e1) {
log.debug("destroy() failed for failed Server ", e1);
}
return;
}
long t2 = System.nanoTime();
if(log.isInfoEnabled()) {
log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");
}
// Register shutdown hook 钩子
if (useShutdownHook) {
if (shutdownHook == null) {
shutdownHook = new CatalinaShutdownHook();
}
Runtime.getRuntime().addShutdownHook(shutdownHook);
// If JULI is being used, disable JULI's shutdown hook since
// shutdown hooks run in parallel and log messages may be lost
// if JULI's hook completes before the CatalinaShutdownHook()
LogManager logManager = LogManager.getLogManager();
if (logManager instanceof ClassLoaderLogManager) {
((ClassLoaderLogManager) logManager).setUseShutdownHook(
false);
}
}
if (await) {
await();
stop();
}
}
- getServer().start(),方法启动Server,源码分析
# 1.LifecycleBase的start()方法
@Override
public final synchronized void start() throws LifecycleException {
if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||
LifecycleState.STARTED.equals(state)) {
if (log.isDebugEnabled()) {
Exception e = new LifecycleException();
log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e);
} else if (log.isInfoEnabled()) {
log.info(sm.getString("lifecycleBase.alreadyStarted", toString()));
}
return;
}
if (state.equals(LifecycleState.NEW)) {
init();
} else if (state.equals(LifecycleState.FAILED)) {
stop();
} else if (!state.equals(LifecycleState.INITIALIZED) &&
!state.equals(LifecycleState.STOPPED)) {
invalidTransition(Lifecycle.BEFORE_START_EVENT);
}
try {
setStateInternal(LifecycleState.STARTING_PREP, null, false);
//启动子类的StandardServer(重点)
startInternal();
if (state.equals(LifecycleState.FAILED)) {
// This is a 'controlled' failure. The component put itself into the
// FAILED state so call stop() to complete the clean-up.
stop();
} else if (!state.equals(LifecycleState.STARTING)) {
// Shouldn't be necessary but acts as a check that sub-classes are
// doing what they are supposed to.
invalidTransition(Lifecycle.AFTER_START_EVENT);
} else {
setStateInternal(LifecycleState.STARTED, null, false);
}
} catch (Throwable t) {
// This is an 'uncontrolled' failure so put the component into the
// FAILED state and throw an exception.
ExceptionUtils.handleThrowable(t);
setStateInternal(LifecycleState.FAILED, null, false);
throw new LifecycleException(sm.getString("lifecycleBase.startFail", toString()), t);
}
}
# 2.standardServer的startInternal()方法
@Override
protected void startInternal() throws LifecycleException {
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING);
globalNamingResources.start();
// Start our defined Services
synchronized (servicesLock) {
for (int i = 0; i < services.length; i++) {
//启动services(重点)
services[i].start();
}
}
}
Server的初始化start()方法,会先调用父类LifecycleBase的start()方法,然后再调用子类Server的startInternal()方法
这个调用的模式:父类start--->子类startInternal,在后面的services,connector,engine初始化是一样的模式。
- services[i].start(),启动services,源码分析
# 1.standardService的startInternal()方法
@Override
protected void startInternal() throws LifecycleException {
if(log.isInfoEnabled())
log.info(sm.getString("standardService.start.name", this.name));
setState(LifecycleState.STARTING);
//启动engine(重点)
// Start our defined Container first
if (engine != null) {
synchronized (engine) {
engine.start();
}
}
synchronized (executors) {
for (Executor executor: executors) {
executor.start();
}
}
//启动mapperListener
mapperListener.start();
// Start our defined Connectors second
synchronized (connectorsLock) {
for (Connector connector: connectors) {
try {
// If it has already failed, don't try and start it
if (connector.getState() != LifecycleState.FAILED) {
//启动connector(重点)
connector.start();
}
} catch (Exception e) {
log.error(sm.getString(
"standardService.connector.startFailed",
connector), e);
}
}
}
}
从services的启动分析,可以得到services的启动,会启动engine和connector。(executor、mapperListener)
- connector.start(),启动Connector,源码分析
# 1.Connector的startInternal()方法
@Override
protected void startInternal() throws LifecycleException {
// Validate settings before starting
if (getPort() < 0) {
throw new LifecycleException(sm.getString(
"coyoteConnector.invalidPort", Integer.valueOf(getPort())));
}
setState(LifecycleState.STARTING);
try {
//启动protocolHandler(重点)
protocolHandler.start();
} catch (Exception e) {
throw new LifecycleException(
sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
}
}
# 2.AbstractProtocol下protocolHandler的启动start()方法
@Override
public void start() throws Exception {
if (getLog().isInfoEnabled()) {
getLog().info(sm.getString("abstractProtocolHandler.start", getName()));
}
//启动endpoint
endpoint.start();
// Start async timeout thread
asyncTimeout = new AsyncTimeout();
Thread timeoutThread = new Thread(asyncTimeout, getNameInternal() + "-AsyncTimeout");
int priority = endpoint.getThreadPriority();
if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
priority = Thread.NORM_PRIORITY;
}
timeoutThread.setPriority(priority);
timeoutThread.setDaemon(true);
timeoutThread.start();
}
# 3.AbstractEndpoint下endpoint的启动start()方法
public final void start() throws Exception {
if (bindState == BindState.UNBOUND) {
bind();
bindState = BindState.BOUND_ON_START;
}
startInternal();
}
从connector的启动分析,可以得到connector的启动,会启动protocolHandler和endpoint
- engine.start(),启动engine,源码分析
# 1.StandardEngine的startInternal()方法
@Override
protected synchronized void startInternal() throws LifecycleException {
// Log our server identification information
if(log.isInfoEnabled())
log.info( "Starting Servlet Engine: " + ServerInfo.getServerInfo());
// Standard container startup
super.startInternal();
}
# 2.ContainerBase的startInternal()方法
@Override
protected synchronized void startInternal() throws LifecycleException {
// Start our subordinate components, if any
logger = null;
//日志处理
getLogger();
//有集群启动集群
Cluster cluster = getClusterInternal();
if (cluster instanceof Lifecycle) {
((Lifecycle) cluster).start();
}
//域处理
Realm realm = getRealmInternal();
if (realm instanceof Lifecycle) {
((Lifecycle) realm).start();
}
//启动所有子容器 StandardHost, StandardContext, StandardWrapper
Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<>();
for (int i = 0; i < children.length; i++) {
results.add(startStopExecutor.submit(new StartChild(children[i])));
}
MultiThrowable multiThrowable = null;
//开启线程启动子容器
for (Future<Void> result : results) {
try {
//阻塞,让子容器启动完成再执行下面的代码
result.get();
} catch (Throwable e) {
log.error(sm.getString("containerBase.threadedStartFailed"), e);
if (multiThrowable == null) {
multiThrowable = new MultiThrowable();
}
multiThrowable.add(e);
}
}
if (multiThrowable != null) {
throw new LifecycleException(sm.getString("containerBase.threadedStartFailed"),
multiThrowable.getThrowable());
}
//启用Pipeline管道
// Start the Valves in our pipeline (including the basic), if any
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).start();
}
//设置生命周期的状态starting,激发监听器listener:HostConfig,通过这个去启动Host(重要)
setState(LifecycleState.STARTING);
//开启线程
threadStart();
}
# 3.StandardHost的startInternal()方法
@Override
protected synchronized void startInternal() throws LifecycleException {
//设置错误报告
// Set error report valve
String errorValve = getErrorReportValveClass();
if ((errorValve != null) && (!errorValve.equals(""))) {
try {
boolean found = false;
Valve[] valves = getPipeline().getValves();
for (Valve valve : valves) {
if (errorValve.equals(valve.getClass().getName())) {
found = true;
break;
}
}
if(!found) {
Valve valve =
(Valve) Class.forName(errorValve).getConstructor().newInstance();
getPipeline().addValve(valve);
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error(sm.getString(
"standardHost.invalidErrorReportValveClass",
errorValve), t);
}
}
//再次调用父类ContainerBase
super.startInternal();
}
# 4.LifecycleBase.setState(LifecycleState.STARTING); 改变生命周期的状态,激发监听器listener:HostConfig。
protected synchronized void setState(LifecycleState state) throws LifecycleException {
setStateInternal(state, null, true);
}
private synchronized void setStateInternal(LifecycleState state,
Object data, boolean check) throws LifecycleException {
this.state = state;
String lifecycleEvent = state.getLifecycleEvent();
if (lifecycleEvent != null) {
fireLifecycleEvent(lifecycleEvent, data);
}
}
protected void fireLifecycleEvent(String type, Object data) {
LifecycleEvent event = new LifecycleEvent(this, type, data);
for (LifecycleListener listener : lifecycleListeners) {
//这个listener就是hostConfig(重点)
listener.lifecycleEvent(event);
}
}
# 5.HostConfig的start()
public void lifecycleEvent(LifecycleEvent event) {
// Process the event that has occurred
if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) {
check();
} else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
beforeStart();
} else if (event.getType().equals(Lifecycle.START_EVENT)) {
//执行hostConfig的start()方法
start();
} else if (event.getType().equals(Lifecycle.STOP_EVENT)) {
stop();
}
}
public void start() {
...
//部署webapps
if (host.getDeployOnStartup())
deployApps();
}
# 6.部署webapps
protected void deployApps() {
File appBase = host.getAppBaseFile();
File configBase = host.getConfigBaseFile();
String[] filteredAppPaths = filterAppPaths(appBase.list());
//部署xml文件配置的server.xml <host><context>...
// Deploy XML descriptors from configBase
deployDescriptors(configBase, configBase.list());
//部署war包
// Deploy WARs
deployWARs(appBase, filteredAppPaths);
//部署文件夹
// Deploy expanded folders
deployDirectories(appBase, filteredAppPaths);
}
# 7.部署文件夹deployDirectories()
protected void deployDirectories(File appBase, String[] files) {
//发布文件夹
if (files == null)
return;
//使用future和线程池的技术
ExecutorService es = host.getStartStopExecutor();
List<Future<?>> results = new ArrayList<>();
for (int i = 0; i < files.length; i++) {
if (files[i].equalsIgnoreCase("META-INF"))
continue;
if (files[i].equalsIgnoreCase("WEB-INF"))
continue;
File dir = new File(appBase, files[i]);
if (dir.isDirectory()) {
ContextName cn = new ContextName(files[i], false);
if (isServiced(cn.getName()) || deploymentExists(cn.getName()))
continue;
//submit(Runnable),接收一个Runnable,会返回一个Future
//new DeployDirectory(重点)
results.add(es.submit(new DeployDirectory(this, cn, dir)));
}
}
//如果任务结束执行则返回null(会等待线程执行完)
for (Future<?> result : results) {
try {
result.get();
} catch (Exception e) {
log.error(sm.getString(
"hostConfig.deployDir.threaded.error"), e);
}
}
}
//实现runnable接口
private static class DeployDirectory implements Runnable {
private HostConfig config;
private ContextName cn;
private File dir;
public DeployDirectory(HostConfig config, ContextName cn, File dir) {
this.config = config;
this.cn = cn;
this.dir = dir;
}
@Override
public void run() {
//部署文件夹
config.deployDirectory(cn, dir);
}
}
# 8.部署文件夹deployDirectory()
protected void deployDirectory(ContextName cn, File dir) {
long startTime = 0;
// Deploy the application in this directory
if( log.isInfoEnabled() ) {
startTime = System.currentTimeMillis();
log.info(sm.getString("hostConfig.deployDir",
dir.getAbsolutePath()));
}
//拿到context
Context context = null;
File xml = new File(dir, Constants.ApplicationContextXml);
File xmlCopy = new File(host.getConfigBaseFile(), cn.getBaseName() + ".xml");
DeployedApplication deployedApp;
boolean copyThisXml = isCopyXML();
boolean deployThisXML = isDeployThisXML(dir, cn);
try {
if (deployThisXML && xml.exists()) {
synchronized (digesterLock) {
try {
//解析context节点
context = (Context) digester.parse(xml);
}
}
} else if (!deployThisXML && xml.exists()) {
context = new FailedContext();
} else {
context = (Context) Class.forName(contextClass).getConstructor().newInstance();
}
//实例化 ContextConfig,作为 LifecycleListener 添加到 Context 容器中
//这和 StandardHost 的套路一样,都是使用 XXXConfig
Class<?> clazz = Class.forName(host.getConfigClass());
LifecycleListener listener = (LifecycleListener) clazz.getConstructor().newInstance();
context.addLifecycleListener(listener);
context.setName(cn.getName());
context.setPath(cn.getPath());
context.setWebappVersion(cn.getVersion());
context.setDocBase(cn.getBaseName());
//把context添加到子节点,然后启动context(重点)
host.addChild(context);
}
}
从standardEngine的启动过程,可以看出,主要是启动standardHost。
然后通过监听器技术,启动HostConfig,进而解析webapps,启动context。HostConfig的deployDirectory,主要做了几个工作:
1.使用 digester,或者反射实例化 StandardContext
2.实例化ContextConfig,并且为Context 容器注册事件监听器,和 StandardHost 的套路一样,借助 XXXConfig 完成容器的启动、停止工作
- 将当前 Context 实例作为子容器添加到Host 容器中,添加子容器的逻辑在 ContainerBase 中已经实现了,如果当前 Container 的状态是 STARTING_PREP 并且 startChildren 为 true,则还会启动子容器
- StandardContext的startInternal()方法分析
# 1.StandardContext的startInternal()方法
@Override
protected synchronized void startInternal() throws LifecycleException {
//StandardContext启动
if(log.isDebugEnabled())
log.debug("Starting " + getBaseName());
//发布这个状态,广播出去,让其他监听
// Send j2ee.state.starting notification
if (this.getObjectName() != null) {
Notification notification = new Notification("j2ee.state.starting",
this.getObjectName(), sequenceNumber.getAndIncrement());
broadcaster.sendNotification(notification);
}
setConfigured(false);
boolean ok = true;
//启动命名空间资源
// Currently this is effectively a NO-OP but needs to be called to
// ensure the NamingResources follows the correct lifecycle
if (namingResources != null) {
namingResources.start();
}
//创建工作目录work
// Post work directory
postWorkDirectory();
//加载资源
// Add missing components as necessary
if (getResources() == null) { // (1) Required by Loader
if (log.isDebugEnabled())
log.debug("Configuring default Resources");
try {
setResources(new StandardRoot(this));
} catch (IllegalArgumentException e) {
log.error(sm.getString("standardContext.resourcesInit"), e);
ok = false;
}
}
if (ok) {
resourcesStart();
}
//Webapp加载器
if (getLoader() == null) {
WebappLoader webappLoader = new WebappLoader(getParentClassLoader());
webappLoader.setDelegate(getDelegate());
setLoader(webappLoader);
}
//初始化一个cookie
// An explicit cookie processor hasn't been specified; use the default
if (cookieProcessor == null) {
cookieProcessor = new Rfc6265CookieProcessor();
}
//字符集的映射
// Initialize character set mapper
getCharsetMapper();
//依赖关系处理
// Validate required extensions
boolean dependencyCheck = true;
try {
dependencyCheck = ExtensionValidator.validateApplication
(getResources(), this);
} catch (IOException ioe) {
log.error(sm.getString("standardContext.extensionValidationError"), ioe);
dependencyCheck = false;
}
if (!dependencyCheck) {
// do not make application available if dependency check fails
ok = false;
}
//用户命名属性,获取环境变量
// Reading the "catalina.useNaming" environment variable
String useNamingProperty = System.getProperty("catalina.useNaming");
if ((useNamingProperty != null)
&& (useNamingProperty.equals("false"))) {
useNaming = false;
}
if (ok && isUseNaming()) {
if (getNamingContextListener() == null) {
NamingContextListener ncl = new NamingContextListener();
ncl.setName(getNamingContextName());
ncl.setExceptionOnFailedWrite(getJndiExceptionOnFailedWrite());
addLifecycleListener(ncl);
setNamingContextListener(ncl);
}
}
// Standard container startup
if (log.isDebugEnabled())
log.debug("Processing standard container startup");
// Binding thread
ClassLoader oldCCL = bindThread();
//发出一个生命周期事件,触发监听器:ContextConfig(重点)
fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);
//启动wrapper子节点(重点)
// Start our child containers, if not already started
for (Container child : findChildren()) {
if (!child.getState().isAvailable()) {
child.start();
}
}
}
# 2.ContextConfig的configureStart()方法
protected synchronized void configureStart() {
//解析web.xml(重点)
//解析servlet,filter,listener
webConfig();
}
protected void webConfig() {
//创建web.xml解析器
WebXmlParser webXmlParser = new WebXmlParser(context.getXmlNamespaceAware(),
context.getXmlValidation(), context.getXmlBlockExternal());
Set<WebXml> defaults = new HashSet<>();
defaults.add(getDefaultWebXmlFragment(webXmlParser));
WebXml webXml = createWebXml();
//解析web.xml
InputSource contextWebXml = getContextWebXmlSource();
if (!webXmlParser.parseWebXml(contextWebXml, webXml, false)) {
ok = false;
}
ServletContext sContext = context.getServletContext();
// Ordering is important here
// Step 1. Identify all the JARs packaged with the application and those
// provided by the container. If any of the application JARs have a
// web-fragment.xml it will be parsed at this point. web-fragment.xml
// files are ignored for container provided JARs.
Map<String,WebXml> fragments = processJarsForWebFragments(webXml, webXmlParser);
// Step 2. Order the fragments.
Set<WebXml> orderedFragments = null;
orderedFragments =
WebXml.orderWebFragments(webXml, fragments, sContext);
// Step 3. Look for ServletContainerInitializer implementations
if (ok) {
processServletContainerInitializers();
}
if (!webXml.isMetadataComplete() || typeInitializerMap.size() > 0) {
// Steps 4 & 5.
processClasses(webXml, orderedFragments);
}
if (!webXml.isMetadataComplete()) {
// Step 6. Merge web-fragment.xml files into the main web.xml
// file.
if (ok) {
ok = webXml.merge(orderedFragments);
}
// Step 7. Apply global defaults
// Have to merge defaults before JSP conversion since defaults
// provide JSP servlet definition.
webXml.merge(defaults);
// Step 8. Convert explicitly mentioned jsps to servlets
if (ok) {
convertJsps(webXml);
}
// Step 9. Apply merged web.xml to Context
if (ok) {
//配置context
configureContext(webXml);
}
} else {
webXml.merge(defaults);
convertJsps(webXml);
configureContext(webXml);
}
if (context.getLogEffectiveWebXml()) {
log.info("web.xml:\n" + webXml.toXml());
}
// Always need to look for static resources
// Step 10. Look for static resources packaged in JARs
if (ok) {
// Spec does not define an order.
// Use ordered JARs followed by remaining JARs
Set<WebXml> resourceJars = new LinkedHashSet<>();
for (WebXml fragment : orderedFragments) {
resourceJars.add(fragment);
}
for (WebXml fragment : fragments.values()) {
if (!resourceJars.contains(fragment)) {
resourceJars.add(fragment);
}
}
processResourceJARs(resourceJars);
// See also StandardContext.resourcesStart() for
// WEB-INF/classes/META-INF/resources configuration
}
// Step 11. Apply the ServletContainerInitializer config to the
// context
if (ok) {
for (Map.Entry<ServletContainerInitializer,
Set<Class<?>>> entry :
initializerClassMap.entrySet()) {
if (entry.getValue().isEmpty()) {
context.addServletContainerInitializer(
entry.getKey(), null);
} else {
context.addServletContainerInitializer(
entry.getKey(), entry.getValue());
}
}
}
// 指定 ServletContext 的相关参数
mergeParameters();
// 调用 ServletContainerInitializer#onStartup()
for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :
initializers.entrySet()) {
try {
entry.getKey().onStartup(entry.getValue(),getServletContext());
} catch (ServletException e) {
log.error(sm.getString("standardContext.sciFail"), e);
ok = false;
break;
}
}
//初始化 Filter
if (ok) {
if (!filterStart()) {
log.error(sm.getString("standardContext.filterFail"));
ok = false;
}
}
//处理 Wrapper 容器(如果Servlet的loadOnStartup >= 0,便会在这一阶段完成 Servlet 的加载)
if (ok) {
if (!loadOnStartup(findChildren())){
log.error(sm.getString("standardContext.servletFail"));
ok = false;
}
}
}
StandardContext 和其他 Container 一样,也是重写了 startInternal 方法。由于涉及到 webapp 的启动流程,需要很多准备工作,比如使用 WebResourceRoot 加载资源文件、利用 Loader 加载 class、使用 JarScanner 扫描 jar 包,等等。
因此StandardContext 的启动逻辑比较复杂,这里描述下几个重要的步骤:
- 创建工作目录,比如$CATALINA_HOME\work\Catalina\localhost\examples;实例化 ContextServlet,应用程序拿到的是 ApplicationContext的外观模式
- 实例化 WebResourceRoot,默认实现类是 StandardRoot,用于读取 webapp 的文件资源
- 实例化 Loader 对象,Loader 是 tomcat 对于 ClassLoader 的封装,用于支持在运行期间热加载 class
- 发出 CONFIGURE_START_EVENT 事件,ContextConfig 会处理该事件,主要目的是从 webapp 中读取 servlet 相关的 Listener、Servlet、Filter 等
- 实例化 Sesssion 管理器,默认使用 StandardManager
- 调用 listenerStart,实例化 servlet 相关的各种 Listener,并且调用
ServletContextListener
- 处理 Filter
- 加载 Servlet
- 触发 CONFIGURE_START_EVENT 事件,触发ContextConfig监听器
ContextConfig 它是一个 LifycycleListener,它在 Context 启动过程中是承担了一个非常重要的角色。StandardContext 会发出 CONFIGURE_START_EVENT 事件,而 ContextConfig 会处理该事件,主要目的是通过 web.xml 或者 Servlet3.0 的注解配置,读取 Servlet 相关的配置信息,比如 Filter、Servlet、Listener 等,其核心逻辑在 ContextConfig#webConfig() 方法中实现。
ContextConfig执行的重要步骤:
- 是通过 WebXmlParser 对 web.xml 进行解析,如果存在 web.xml 文件,则会把文件中定义的 Servlet、Filter、Listener 注册到 WebXml 实例中
- 如果没有 web.xml 文件,tomcat 会先扫描 WEB-INF/classes 目录下面的 class 文件,然后扫描 WEB-INF/lib 目录下面的 jar 包,解析字节码读取 servlet 相关的注解配置类,这里不得不吐槽下 serlvet3.0 注解,对 servlet 注解的处理相当重量级。tomcat 不会预先把该 class 加载到 jvm 中,而是通过解析字节码文件,获取对应类的一些信息,比如注解、实现的接口等
- Step 9:往 Context 中添加子容器 Wrapper
# 1.context添加wrapper子节点
private void configureContext(WebXml webxml) {
// 设置 Filter 定义
for (FilterDef filter : webxml.getFilters().values()) {
if (filter.getAsyncSupported() == null) {
filter.setAsyncSupported("false");
}
context.addFilterDef(filter);
}
// 设置 FilterMapping,即 Filter 的 URL 映射
for (FilterMap filterMap : webxml.getFilterMappings()) {
context.addFilterMap(filterMap);
}
// 往 Context 中添加子容器 Wrapper,即 Servlet
for (ServletDef servlet : webxml.getServlets().values()) {
Wrapper wrapper = context.createWrapper();
// 省略若干代码。。。
wrapper.setOverridable(servlet.isOverridable());
context.addChild(wrapper);
}
// ......
}
- 启动 StandardWrapper容器
# 1.StandardWrapper的startInternal()方法
@Override
protected synchronized void startInternal() throws LifecycleException {
// 发出 j2ee.state.starting 事件通知
if (this.getObjectName() != null) {
Notification notification = new Notification("j2ee.state.starting",
this.getObjectName(),
sequenceNumber++);
broadcaster.sendNotification(notification);
}
// ConainerBase 的启动逻辑
super.startInternal();
setAvailable(0L);
// 发出 j2ee.state.running 事件通知
if (this.getObjectName() != null) {
Notification notification =
new Notification("j2ee.state.running", this.getObjectName(), sequenceNumber++);
broadcaster.sendNotification(notification);
}
}
# 2.StandardWrapper的load()方法
@Override
public synchronized void load() throws ServletException {
// 实例化 Servlet,并且调用 init 方法完成初始化
instance = loadServlet();
if (!instanceInitialized) {
initServlet(instance);
}
if (isJspServlet) {
// 处理 jsp Servlet
StringBuilder oname = new StringBuilder(getDomain());
oname.append(":type=JspMonitor");
oname.append(getWebModuleKeyProperties());
oname.append(",name=");
oname.append(getName());
oname.append(getJ2EEKeyProperties());
try {
jspMonitorON = new ObjectName(oname.toString());
Registry.getRegistry(null, null)
.registerComponent(instance, jspMonitorON, null);
} catch( Exception ex ) {
log.info("Error registering JSP monitoring with jmx " +
instance);
}
}
}
StandardWrapper 没有子容器,启动逻辑相对比较简单清晰,它重写了 startInternal 方法,主要是完成了 jmx 的事件通知,先后向 jmx 发出 starting、running 事件由前面对 Context 容器的分析可知,Context 完成 Filter 初始化之后,如果 loadOnStartup >= 0 便会调用 load 方法加载 Wrapper 容器。StandardWrapper 使用 InstanceManager 实例化 Servlet,并且调用 Servlet 的 init 方法进行初始化,传入的 ServletConfig 是 StandardWrapperFacade 对象。
总结:
tomcat 实现了 javax.servlet.ServletContext 接口,在 Context 启动的时候会实例化该对象。由 Context 容器通过 web.xml 或者 扫描 class 字节码读取 servlet3.0 的注解配置,从而加载 webapp 定义的 Listener、Servlet、Filter 等 servlet 组件,但是并不会立即实例化对象。全部加载完毕之后,依次对 Listener、Filter、Servlet 进行实例化、并且调用其初始化方法,比如 ServletContextListener#contextInitialized()、Flter#init() 等到此tomcat的启动阶段就已经完成了。使用的是责任链模式,一步一步的启动。
组件启动的顺序:
Server-->Service-->Engine-->Host-->Context-->Wrapper
- tomcat初始化和启动流程图:
3.Tomcat的web请求处理阶段
- web请求的总体流程图
由前面的tomcat总体架构可以知道,tomcat是由connector来接收用户的请求,然后再交由container处理。
通过跟踪connector的启动过程,先后启动protocolHandler,然后启动了endpoint,然后启动了Acceptor(用来接收请求)
- 通过查看NioEndpoint的主要结构,可以看到该类有三个重要的内部类:Acceptor,Poller,SocketProcessor。
# 1.NioEndpoint的startInternal()方法
@Override
public void startInternal() throws Exception {
if (!running) {
running = true;
paused = false;
processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
socketProperties.getProcessorCache());
eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
socketProperties.getEventCache());
nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
socketProperties.getBufferPool());
//创建工作者线程池
// Create worker collection
if ( getExecutor() == null ) {
createExecutor();
}
initializeConnectionLatch();
//启动poller线程,用来轮询检查新的请求
// Start poller threads
pollers = new Poller[getPollerThreadCount()];
for (int i=0; i<pollers.length; i++) {
pollers[i] = new Poller();
Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-"+i);
pollerThread.setPriority(threadPriority);
pollerThread.setDaemon(true);
pollerThread.start();
}
//启动Acceptor线程,用来接收用户请求
startAcceptorThreads();
}
}
# 2.启动Acceptor线程
protected final void startAcceptorThreads() {
//获取Acceptor线程数(默认是1)
int count = getAcceptorThreadCount();
//创建Acceptor数组
acceptors = new Acceptor[count];
for (int i = 0; i < count; i++) {
//创建Acceptor对象,Acceptor继承Runnable
acceptors[i] = createAcceptor();
String threadName = getName() + "-Acceptor-" + i;
acceptors[i].setThreadName(threadName);
//创建Thread对象
Thread t = new Thread(acceptors[i], threadName);
t.setPriority(getAcceptorThreadPriority());
t.setDaemon(getDaemon());
//启动线程
t.start();
}
}
由上面的代码可以看出NioEndpoint在执行startInternal()方法时候,会启动Acceptor线程。Acceptor继承了Runnable,然后使用Thread启动了Acceptor线程。
- Acceptor run()方法分析
# 1.Acceptor 用来接收请求
protected class Acceptor extends AbstractEndpoint.Acceptor {
@Override
public void run() {
int errorDelay = 0;
System.out.println("Acceptor 接收者开始执行");
// Loop until we receive a shutdown command
while (running) {
// Loop if endpoint is paused
while (paused && running) {
state = AcceptorState.PAUSED;
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// Ignore
}
}
if (!running) {
break;
}
state = AcceptorState.RUNNING;
try {
//if we have reached max connections, wait
countUpOrAwaitConnection();
SocketChannel socket = null;
try {
//接收请求,拿到socket
socket = serverSock.accept();
} catch (IOException ioe) {
// We didn't get a socket
countDownConnection();
if (running) {
// Introduce delay if necessary
errorDelay = handleExceptionWithDelay(errorDelay);
// re-throw
throw ioe;
} else {
break;
}
}
// Successful accept, reset the error delay
errorDelay = 0;
// Configure the socket
if (running && !paused) {
//设置socket的一些属性
if (!setSocketOptions(socket)) {
closeSocket(socket);
}
} else {
closeSocket(socket);
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error(sm.getString("endpoint.accept.fail"), t);
}
}
state = AcceptorState.ENDED;
}
}
# 2.设置socket的一些属性
protected boolean setSocketOptions(SocketChannel socket) {
// Process the connection
try {
//disable blocking, APR style, we are gonna be polling it
socket.configureBlocking(false);
Socket sock = socket.socket();
socketProperties.setProperties(sock);
//SocketChannel转化成nioChannel
NioChannel channel = nioChannels.pop();
if (channel == null) {
SocketBufferHandler bufhandler = new SocketBufferHandler(
socketProperties.getAppReadBufSize(),
socketProperties.getAppWriteBufSize(),
socketProperties.getDirectBuffer());
if (isSSLEnabled()) { //SSL, https
channel = new SecureNioChannel(socket, bufhandler, selectorPool, this);
} else {
//http1.1
channel = new NioChannel(socket, bufhandler);
}
} else {
channel.setIOChannel(socket);
channel.reset();
}
//获取poller对象,注册channel(重要)
getPoller0().register(channel);
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
try {
log.error("",t);
} catch (Throwable tt) {
ExceptionUtils.handleThrowable(tt);
}
// Tell to close the socket
return false;
}
return true;
}
# 3.poller对象,注册channel。Poller.register()方法
public void register(final NioChannel socket) {
socket.setPoller(this);
NioSocketWrapper ka = new NioSocketWrapper(socket, NioEndpoint.this);
socket.setSocketWrapper(ka);
ka.setPoller(this);
ka.setReadTimeout(getSocketProperties().getSoTimeout());
ka.setWriteTimeout(getSocketProperties().getSoTimeout());
ka.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());
ka.setSecure(isSSLEnabled());
ka.setReadTimeout(getConnectionTimeout());
ka.setWriteTimeout(getConnectionTimeout());
PollerEvent r = eventCache.pop();
//生成poller, socket加入到even queue
ka.interestOps(SelectionKey.OP_READ);//this is what OP_REGISTER turns into.
if ( r==null) r = new PollerEvent(socket,ka,OP_REGISTER);
else r.reset(socket,ka,OP_REGISTER);
addEvent(r);
}
通过查看Acceptor的run方法,可以看到拿到socket对象。(说明tomcat的底层是通过socket通信的)
然后就通过生成poller。Poller线程主要用于以较少的资源轮询已连接套接字以保持连接,当数据可用时转给工作线程。
- Poller 轮询,检验是否有新的请求
# 1.Poller的run()方法
@Override
public void run() {
// Loop until destroy() is called
while (true) {
boolean hasEvents = false;
try {
if (!close) {
//该方法遍历了eventqueue中所有的pollorEvent
//然后依次调用pollorEvent的run方法
//将socket注册到selector中
hasEvents = events();
if (wakeupCounter.getAndSet(-1) > 0) {
keyCount = selector.selectNow();
} else {
keyCount = selector.select(selectorTimeout);
}
wakeupCounter.set(0);
}
if (close) {
events();
timeout(0, false);
try {
selector.close();
} catch (IOException ioe) {
log.error(sm.getString("endpoint.nio.selectorCloseFail"), ioe);
}
break;
}
} catch (Throwable x) {
ExceptionUtils.handleThrowable(x);
log.error("",x);
continue;
}
//either we timed out or we woke up, process events first
if ( keyCount == 0 ) hasEvents = (hasEvents | events());
Iterator<SelectionKey> iterator =
keyCount > 0 ? selector.selectedKeys().iterator() : null;
// Walk through the collection of ready keys and dispatch
// any active event.
while (iterator != null && iterator.hasNext()) {
SelectionKey sk = iterator.next();
NioSocketWrapper attachment = (NioSocketWrapper)sk.attachment();
// Attachment may be null if another thread has called
// cancelledKey()
if (attachment == null) {
iterator.remove();
} else {
iterator.remove();
//处理(重点)
processKey(sk, attachment);
}
}//while
//process timeouts
timeout(keyCount,hasEvents);
}//while
getStopLatch().countDown();
}
# 2.Poller,处理processKey
protected void processKey(SelectionKey sk, NioSocketWrapper attachment) {
try {
if ( close ) {
cancelledKey(sk);
} else if ( sk.isValid() && attachment != null ) {
if (sk.isReadable() || sk.isWritable() ) {
if ( attachment.getSendfileData() != null ) {
processSendfile(sk,attachment, false);
} else {
unreg(sk, attachment, sk.readyOps());
boolean closeSocket = false;
// Read goes before write
//读事件
if (sk.isReadable()) {
//处理socket(创建worker,重点)
if (!processSocket(attachment, SocketEvent.OPEN_READ, true)) {
closeSocket = true;
}
}
//写事件
if (!closeSocket && sk.isWritable()) {
if (!processSocket(attachment, SocketEvent.OPEN_WRITE, true)) {
closeSocket = true;
}
}
if (closeSocket) {
cancelledKey(sk);
}
}
}
} else {
//invalid key
cancelledKey(sk);
}
} catch ( CancelledKeyException ckx ) {
cancelledKey(sk);
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error("",t);
}
}
Poller线程主要用于以较少的资源轮询已连接套接字以保持连接,当数据可用时转给工作线程
通过对Poller的run方法跟踪,可以看到会创建SocketProcessor(worker)对socket的进一步处理。
- SocketProcessor (worker) 处理socket过程。
# 1.AbstractEndpoint的processSocket()方法
//处理socket
public boolean processSocket(SocketWrapperBase<S> socketWrapper,
SocketEvent event, boolean dispatch) {
try {
if (socketWrapper == null) {
return false;
}
//创建SocketProcessor处理器(worker)
SocketProcessorBase<S> sc = processorCache.pop();
if (sc == null) {
sc = createSocketProcessor(socketWrapper, event);
} else {
sc.reset(socketWrapper, event);
}
//执行
Executor executor = getExecutor();
if (dispatch && executor != null) {
executor.execute(sc);
} else {
sc.run();
}
} catch (RejectedExecutionException ree) {
getLog().warn(sm.getString("endpoint.executor.fail", socketWrapper) , ree);
return false;
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
// This means we got an OOM or similar creating a thread, or that
// the pool and its queue are full
getLog().error(sm.getString("endpoint.process.fail"), t);
return false;
}
return true;
}
- SocketProcessor 的 doRun()分析。
# 1.SocketProcessor的doRun()方法
protected class SocketProcessor extends SocketProcessorBase<NioChannel> {
public SocketProcessor(SocketWrapperBase<NioChannel> socketWrapper, SocketEvent event) {
super(socketWrapper, event);
}
@Override
protected void doRun() {
NioChannel socket = socketWrapper.getSocket();
SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
try {
int handshake = -1;
if (handshake == 0) {
SocketState state = SocketState.OPEN;
// Process the request from this socket
if (event == null) {
//处理socket(重点)
state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
} else {
state = getHandler().process(socketWrapper, event);
}
if (state == SocketState.CLOSED) {
close(socket, key);
}
}
}
}
}
# 2.AbstractProtocol的ConnectionHandler的process()方法。(只贴出重点关注代码)
@Override
public SocketState process(SocketWrapperBase<S> wrapper, SocketEvent status) {
//拿到socket对象
S socket = wrapper.getSocket();
Processor processor = connections.get(socket);
if (processor == null) {
//创建Processor(重点)
processor = getProtocol().createProcessor();
register(processor);
}
//通过processor执行wrapper(重点)
state = processor.process(wrapper, status);
// Make sure socket/processor is removed from the list of current
// connections
connections.remove(socket);
release(processor);
return SocketState.CLOSED;
}
# 3.AbstractHttp11Protocol.createProcessor()方法。 创建Processor。
protected Processor createProcessor() {
//构建Http11Processor
Http11Processor processor = new Http11Processor(getMaxHttpHeaderSize(),
getAllowHostHeaderMismatch(), getRejectIllegalHeaderName(), getEndpoint(),
getMaxTrailerSize(), allowedTrailerHeaders, getMaxExtensionSize(),
getMaxSwallowSize(), httpUpgradeProtocols, getSendReasonPhrase(),
relaxedPathChars, relaxedQueryChars);
//设置adapter适配器(重点)
processor.setAdapter(getAdapter());
//默认的keepAlive情况下,每个socket处理的最多的 请求次数
processor.setMaxKeepAliveRequests(getMaxKeepAliveRequests());
//开启keepAlive的Timeout
processor.setConnectionUploadTimeout(getConnectionUploadTimeout());
//http当遇到文件上传时 默认超时时间(300*1000)
processor.setDisableUploadTimeout(getDisableUploadTimeout());
//当http请求的body size超过这个值时,通过gzip进行压缩
processor.setCompressionMinSize(getCompressionMinSize());
//http请求是否开启compression处理,gzip压缩
processor.setCompression(getCompression());
processor.setNoCompressionUserAgents(getNoCompressionUserAgents());
//http body里面的内容是“text/html,text/xml,text/plain”
//才会进行压缩处理
processor.setCompressibleMimeTypes(getCompressibleMimeTypes());
processor.setRestrictedUserAgents(getRestrictedUserAgents());
//最大的post处理尺寸的大小 4*1000
processor.setMaxSavePostSize(getMaxSavePostSize());
processor.setServer(getServer());
processor.setServerRemoveAppProvidedValues(getServerRemoveAppProvidedValues());
return processor;
}
# 4.通过processor执行wrapper(AbstractProcessorLight.process()方法)
@Override
public SocketState process(SocketWrapperBase<?> socketWrapper, SocketEvent status)
throws IOException {
SocketState state = SocketState.CLOSED;
Iterator<DispatchType> dispatches = null;
do {
if (dispatches != null) {
DispatchType nextDispatch = dispatches.next();
state = dispatch(nextDispatch.getSocketStatus());
} else if (status == SocketEvent.DISCONNECT) {
// Do nothing here, just wait for it to get recycled
} else if (isAsync() || isUpgrade() || state == SocketState.ASYNC_END) {
state = dispatch(status);
if (state == SocketState.OPEN) {
//执行service方法,处理socket(重点)
state = service(socketWrapper);
}
} else if (status == SocketEvent.OPEN_WRITE) {
// Extra write event likely after async, ignore
state = SocketState.LONG;
} else if (status == SocketEvent.OPEN_READ){
state = service(socketWrapper);
} else {
state = SocketState.CLOSED;
}
if (dispatches == null || !dispatches.hasNext()) {
// Only returns non-null iterator if there are
// dispatches to process.
dispatches = getIteratorAndClearDispatches();
}
} while (state == SocketState.ASYNC_END ||
dispatches != null && state != SocketState.CLOSED);
return state;
}
# 5.Http11Processor的service()方法(只保留重点代码)
@Override
public SocketState service(SocketWrapperBase<?> socketWrapper){
//通过adapter处理请求(重点)
getAdapter().service(request, response);
}
通过上面的代码分析,SocketProcessor 在处理socket对象,最终是通过调用getAdapter().service(request, response)方法处理。
- 下面进入到getAdapter().service(request, response)方法分析。
# 1.CoyoteAdapter的service()方法
@Override
public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)
throws Exception { //接收到所有的请求
//转换request和response
Request request = (Request) req.getNote(ADAPTER_NOTES);
Response response = (Response) res.getNote(ADAPTER_NOTES);
if (request == null) {
//通过connector创建request和response
request = connector.createRequest();
request.setCoyoteRequest(req);
response = connector.createResponse();
response.setCoyoteResponse(res);
//link将request和response连接起来
request.setResponse(response);
response.setRequest(request);
// Set as notes
req.setNote(ADAPTER_NOTES, request);
res.setNote(ADAPTER_NOTES, response);
//设置URI的编码
req.getParameters().setQueryStringCharset(connector.getURICharset());
}
if (connector.getXpoweredBy()) {
response.addHeader("X-Powered-By", POWERED_BY);
}
boolean async = false;
boolean postParseSuccess = false;
req.getRequestProcessor().setWorkerThreadName(THREAD_NAME.get());
try {
// Parse and set Catalina and configuration specific
// request parameters
//在map里面解析业务请求(重要)
postParseSuccess = postParseRequest(req, request, res, response);
if (postParseSuccess) {
//设置异步支持(getContainer()拿到的是engine)
//check valves if we support async
request.setAsyncSupported(
connector.getService().getContainer().getPipeline().isAsyncSupported());
// Calling the container
//执行pipeline管道(invoke)standardEngineValve.invoke (重点)
connector.getService().getContainer().getPipeline().getFirst().invoke(
request, response);
}
if (request.isAsync()) {
} else {
//请求和响应完成
request.finishRequest();
response.finishResponse();
}
}
}
# 2.standardEngineValve.invoke()方法
@Override
public final void invoke(Request request, Response response)
throws IOException, ServletException {
//获取StandardHost对象
// Select the Host to be used for this Request
Host host = request.getHost();
if (host == null) {
response.sendError
(HttpServletResponse.SC_BAD_REQUEST,
sm.getString("standardEngine.noHost",
request.getServerName()));
return;
}
if (request.isAsyncSupported()) {
request.setAsyncSupported(host.getPipeline().isAsyncSupported());
}
//执行standardHostValue.invoke()方法(重点)
// Ask this Host to process this request
host.getPipeline().getFirst().invoke(request, response);
}
# 3.standardHostValue.invoke()方法
@Override
public final void invoke(Request request, Response response)
throws IOException, ServletException {
//获取standardContext
Context context = request.getContext();
if (context == null) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
sm.getString("standardHost.noContext"));
return;
}
if (request.isAsyncSupported()) {
request.setAsyncSupported(context.getPipeline().isAsyncSupported());
}
boolean asyncAtStart = request.isAsync();
boolean asyncDispatching = request.isAsyncDispatching();
try {
context.bind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);
if (!asyncAtStart && !context.fireRequestInitEvent(request.getRequest())) {
return;
}
try {
if (!asyncAtStart || asyncDispatching) {
//执行standardContextValue.invoke()的方法(重点)
context.getPipeline().getFirst().invoke(request, response);
}
}
}
}
# 4.standardContextValue.invoke()方法
@Override
public final void invoke(Request request, Response response)
throws IOException, ServletException {
//获取StandardWrapper
// Select the Wrapper to be used for this Request
Wrapper wrapper = request.getWrapper();
if (wrapper == null || wrapper.isUnavailable()) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
if (request.isAsyncSupported()) {
request.setAsyncSupported(wrapper.getPipeline().isAsyncSupported());
}
//执行standardWrapperValue.invoke()的方法(重点)
wrapper.getPipeline().getFirst().invoke(request, response);
}
# 5.standardWrapperValue.invoke()方法
//最终找到servlet处理
@Override
public final void invoke(Request request, Response response)
throws IOException, ServletException {
// Initialize local variables we may need
boolean unavailable = false;
Throwable throwable = null;
// This should be a Request attribute...
long t1=System.currentTimeMillis();
//增加请求次数,CAS
requestCount.incrementAndGet();
StandardWrapper wrapper = (StandardWrapper) getContainer();
//获取servlet对象
Servlet servlet = null;
Context context = (Context) wrapper.getParent();
// Check for the application being marked unavailable
if (!context.getState().isAvailable()) {
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardContext.isUnavailable"));
unavailable = true;
}
// Check for the servlet being marked unavailable
if (!unavailable && wrapper.isUnavailable()) {
container.getLogger().info(sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
long available = wrapper.getAvailable();
if ((available > 0L) && (available < Long.MAX_VALUE)) {
response.setDateHeader("Retry-After", available);
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
} else if (available == Long.MAX_VALUE) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
sm.getString("standardWrapper.notFound",
wrapper.getName()));
}
unavailable = true;
}
//Servlet默认的是在第一次请求的时候实例化
// Allocate a servlet instance to process this request
try {
if (!unavailable) {
//获取不到,再分配加载一个
servlet = wrapper.allocate();
}
} catch (UnavailableException e) {
container.getLogger().error(
sm.getString("standardWrapper.allocateException",
wrapper.getName()), e);
long available = wrapper.getAvailable();
if ((available > 0L) && (available < Long.MAX_VALUE)) {
response.setDateHeader("Retry-After", available);
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
} else if (available == Long.MAX_VALUE) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
sm.getString("standardWrapper.notFound",
wrapper.getName()));
}
} catch (ServletException e) {
container.getLogger().error(sm.getString("standardWrapper.allocateException",
wrapper.getName()), StandardWrapper.getRootCause(e));
throwable = e;
exception(request, response, e);
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
container.getLogger().error(sm.getString("standardWrapper.allocateException",
wrapper.getName()), e);
throwable = e;
exception(request, response, e);
servlet = null;
}
//获取path
MessageBytes requestPathMB = request.getRequestPathMB();
DispatcherType dispatcherType = DispatcherType.REQUEST;
if (request.getDispatcherType()==DispatcherType.ASYNC) dispatcherType = DispatcherType.ASYNC;
request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,dispatcherType);
request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,
requestPathMB);
// Create the filter chain for this request
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
//执行相应的filter过滤器链
// Call the filter chain for this request
// NOTE: This also calls the servlet's service() method
try {
if ((servlet != null) && (filterChain != null)) {
// Swallow output if needed
if (context.getSwallowOutput()) {
try {
SystemLogHandler.startCapture();
if (request.isAsyncDispatching()) {
request.getAsyncContextInternal().doInternalDispatch();
} else {
filterChain.doFilter(request.getRequest(),
response.getResponse());
}
} finally {
String log = SystemLogHandler.stopCapture();
if (log != null && log.length() > 0) {
context.getLogger().info(log);
}
}
} else {
if (request.isAsyncDispatching()) {
request.getAsyncContextInternal().doInternalDispatch();
} else {
filterChain.doFilter
(request.getRequest(), response.getResponse());
}
}
}
} catch (ClientAbortException | CloseNowException e) {
if (container.getLogger().isDebugEnabled()) {
container.getLogger().debug(sm.getString(
"standardWrapper.serviceException", wrapper.getName(),
context.getName()), e);
}
throwable = e;
exception(request, response, e);
} catch (IOException e) {
container.getLogger().error(sm.getString(
"standardWrapper.serviceException", wrapper.getName(),
context.getName()), e);
throwable = e;
exception(request, response, e);
} catch (UnavailableException e) {
container.getLogger().error(sm.getString(
"standardWrapper.serviceException", wrapper.getName(),
context.getName()), e);
// throwable = e;
// exception(request, response, e);
wrapper.unavailable(e);
long available = wrapper.getAvailable();
if ((available > 0L) && (available < Long.MAX_VALUE)) {
response.setDateHeader("Retry-After", available);
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
} else if (available == Long.MAX_VALUE) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
sm.getString("standardWrapper.notFound",
wrapper.getName()));
}
// Do not save exception in 'throwable', because we
// do not want to do exception(request, response, e) processing
} catch (ServletException e) {
Throwable rootCause = StandardWrapper.getRootCause(e);
if (!(rootCause instanceof ClientAbortException)) {
container.getLogger().error(sm.getString(
"standardWrapper.serviceExceptionRoot",
wrapper.getName(), context.getName(), e.getMessage()),
rootCause);
}
throwable = e;
exception(request, response, e);
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
container.getLogger().error(sm.getString(
"standardWrapper.serviceException", wrapper.getName(),
context.getName()), e);
throwable = e;
exception(request, response, e);
}
// Release the filter chain (if any) for this request
if (filterChain != null) {
filterChain.release();
}
// Deallocate the allocated servlet instance
try {
if (servlet != null) {
wrapper.deallocate(servlet);
}
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
container.getLogger().error(sm.getString("standardWrapper.deallocateException",
wrapper.getName()), e);
if (throwable == null) {
throwable = e;
exception(request, response, e);
}
}
// If this servlet has been marked permanently unavailable,
// unload it and release this instance
try {
if ((servlet != null) &&
(wrapper.getAvailable() == Long.MAX_VALUE)) {
wrapper.unload();
}
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
container.getLogger().error(sm.getString("standardWrapper.unloadException",
wrapper.getName()), e);
if (throwable == null) {
throwable = e;
exception(request, response, e);
}
}
}
通过对CoyoteAdapter的service()方法分析,可以知道他是一步一步的调用方法。
StandardEngineValue-->StandardHostValue-->StandardContextValue-->StandardWrapperValue的invoke方法。
- web请求的流程图:
- 附件:tomcat源码(有注释)https://github.com/llsydn/tomcat-source
- tomcat类关系图