图示Tomcat 的顶层结构
Service 连接 container(1)和 connector(N)
A Service is an intermediate component which lives inside a Server and ties one or more Connectors to exactly one Engine.
Service接口的标准实现类 StandardService(implements Lifecycle、service、和MbeanRegistration 接口的所有方法)
注意:同一个service的所有站点共享connector,所以监听端口都一样,除非配置不同的 Service实现区分的端口监听。
主要方法 StandardService.SetContainer
public void setContainer(Container container) {
Container oldContainer = this.container;
//如果已经启动了 container(当前service已经关联container),则结束它的生命周期
if ((oldContainer != null) && (oldContainer instanceof Engine))
((Engine) oldContainer).setService(null);
//替换新的关联
this.container = container;
if ((this.container != null) && (this.container instanceof Engine))
((Engine) this.container).setService(this);
if (started && (this.container != null) && (this.container instanceof Lifecycle)) {
try {
((Lifecycle) this.container).start();
} catch (LifecycleException e) {
;
}
}
//修改container时,需关联到每个connector
synchronized (connectors) {
for (int i = 0; i < connectors.length; i++)
connectors[i].setContainer(this.container);
}
//停止旧的container
if (started && (oldContainer != null) && (oldContainer instanceof Lifecycle)) {
try {
((Lifecycle) oldContainer).stop();
} catch (LifecycleException e) {
;
}
}
support.firePropertyChange("container", oldContainer, this.container);
}
主要方法:StandardService.addConnector
public void addConnector(Connector connector) {
synchronized (connectors) {
connector.setContainer(this.container);
connector.setService(this);
Connector results[] = new Connector[connectors.length + 1];
System.arraycopy(connectors, 0, results, 0, connectors.length);
results[connectors.length] = connector;
connectors = results;
if (initialized) {
try {
connector.initialize();
} catch (LifecycleException e) {
e.printStackTrace(System.err);
}
}
if (started && (connector instanceof Lifecycle)) {
try {
((Lifecycle) connector).start();
} catch (LifecycleException e) {
;
}
}
support.firePropertyChange("connector", null, connector);
}
}
Server 代表整个容器
提供接口让其它程序能够访问到 Service 集合、同时要维护它所包含的所有 Service 的生命周期,包括如何初始化、如何结束服务、如何查询 Service等等,支持className,port,shutdown三个公共属性。
StandardServer.addService
public void addService(Service service) {
service.setServer(this);
synchronized (services) {
Service results[] = new Service[services.length + 1];
System.arraycopy(services, 0, results, 0, services.length);
results[services.length] = service;
services = results;
if (initialized) {
try {
service.initialize();
} catch (LifecycleException e) {
e.printStackTrace(System.err);
}
}
if (started && (service instanceof Lifecycle)) {
try {
((Lifecycle) service).start();
} catch (LifecycleException e) {
;
}
}
support.firePropertyChange("service", null, service);
}
}
Servlet 容器 Container
- Engine 表示一个Servlet引擎,它可以包含一个或多个子容器,比如Host或者Context容器;
- Host 表示一台虚拟的主机,它可以包含一系列Context容器;
- Context 表示一个唯一的ServletContext,一个 Context 对应一个 Web 工程,它可以包含一个 或多个Wrapper容器;
- Wrapper 表示一个独立的Servlet定义,即Wrapper本质就是对Servlet进行了一层包装。
四种容器装配方法:
Engine 和 Host 在 tomcat 的 conf/server.xml 中配置;
Context有三种配置方法:
1. 从文件中配置:
- tomcat 的 conf/server.xml 中的 Context 标签(tomcat重启时重新加载);
- conf/context.xml:所有应用的Context公共配置文件,对所有的应用都起作用;
- conf/[enginename]/[hostname]/context.xml.default(在对应的host中共享);
- conf/[enginename]/[hostname]/appname.xml:*为应用名称;
- 应用自己的 $CATALINA_BASE/webapps/[webappname]/META-INF/context.xml
2. 将WAR应用直接放到host目录下,tomcat会自动查找并添加到host中;
3. 将应用文件夹放到host目录下。
Wrapper 的配置就是在 web.xml 中配置的 servlet,一个 servlet 对应一个 wrapper,conf/web.xml 中配置全局的 Wrapper。例如:
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
四种容器类图关系
tomcat的生命周期管理
Tomcat 通过 org.apache.catalina.Lifecycle 接口统一管理生命周期。所有有生命周期的组件都要实现该接口。该接口一共做四件事:
- 定义LifecycleEvent事件的13种type属性,区分组件发出LifecycleEvent事件时的状态;
- 定义三个管理事件监听器的方法:addLifecycleListener、find、remove;
- 定义四个生命周期的方法:init、start、stop、destroy;
- 定义了获取当前状态的方法:getState和getStateName(返回String类型的状态名字,主要用于JMX中)
Lifecycle 接口的方法的实现都在其它组件中,组件的生命周期由包含它的父组件控制,所以它的 Start 方法自然就是调用它下面的组件的 Start 方法,Stop 方法也是一样。如在 Server 中 Start 方法会调用 Service 组件的 Start 方法,Server 的 Start 方法代码如下:
StandardServer.Start
//事实上,四个生命周期管理方法都需要判断当前状态和要处理的方法是否匹配,不匹配则执行相应的方法使之匹配;同时,执行过程中需要修改该组件的生命周期状态。
public void start() throws LifecycleException {
if (started) {
log.debug(sm.getString("standardServer.start.started"));
return;
}
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true;
synchronized (services) {
for (int i = 0; i < services.length; i++) {
if (services[i] instanceof Lifecycle)
((Lifecycle) services[i]).start();
}
}
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}
StandardServer.Stop
public void stop() throws LifecycleException {
if (!started)
return;
lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
lifecycle.fireLifecycleEvent(STOP_EVENT, null);
started = false;
for (int i = 0; i < services.length; i++) {
if (services[i] instanceof Lifecycle)
((Lifecycle) services[i]).stop();
}
lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
}
附录文件
附录1 \WEB-INF\uCom-servlet.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">
<!--增加本地和Controller扫描路径-->
<context:component-scan base-package="com.urepCompany.**.controller" >
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"
p:messageConverters-ref="messageConverters"/>
<util:list id="messageConverters">
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
</util:list>
<bean id="base.webUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/base/commonImageFileuploadFrameController.do_">repCompany.CommonImageFileuploadFrameController</prop>
<prop key="/base/commonImageDownloadFrameController.do_">repCompany.CommonImageDownloadController</prop>
<prop key="/base/getMilliTime.do_">repCompany.GetMilliTimeController</prop>
</props>
</property>
</bean>
</beans>
参考文献
http://tomcat.apache.org/tomcat-6.0-doc/index.html
https://tomcat.apache.org/tomcat-7.0-doc/api/org/apache/catalina/Lifecycle.html
http://www.ibm.com/developerworks/cn/java/j-lo-tomcat1/
http://stackoverflow.com/questions/18578143/about-multiple-containers-in-spring-framework
https://yq.aliyun.com/articles/20172