2013-10-04
StandardHost是StandardHost.Host的标准实现,继承自ContainerBase基容器,具备容器的功能和特征,在tomcat的结构层次图中位于Engine容器内部,是Engine的子容器,是Context的父容器,负责管理多个Context,即webapp。Host是虚拟主机,一个Engine下面可以有多个虚拟主机。虚拟主机主要做的任务就是负责将Engine中传递过来的请求选择一个合适的Context处理,解决的是Context的选择问题,不同Conext之间数据隔离和共享、数据安全问题,负责根据配置文件生成应用程序的Context。
Host
是tomcat中定义的虚拟主机接口,定义了虚拟主机所需要具备的功能,例如应用文件的磁盘路径,Host的的基路径,校验xml配置文件,发布应用。
ContainerBase
Host继承是基容器具备容器的功能,具有父容器引用,管理子容器和容器中的组件,还有后台任务处理线程。
StandardHostValve
是StandHost的basicvalve,在Host容器pipeline valve链的末端,负责为请求信息选择一个合适的Context处理,控制权转移,控制数据流向。
Host中一些重要的属性
map(String)
请求信息到了Host中,需要为请求选择合适的Context处理,这个方法就是完成这个功能,根据uri选择Context。分析请求URI地址,分解URI,根据URI来定位在当前Host下面的Context,并返回Context。采用的匹配策略是最精确URI匹配规则。
/**
* Return the Context that would be used to process the specified
* host-relative request URI, if any; otherwise return <code>null</code>.
* 根据uri选择合适的Context
* @param uri
* Request URI to be mapped
*/
public Context map(String uri) {
if (log.isDebugEnabled())
log.debug("Mapping request URI '" + uri + "'");
if (uri == null)
return (null);
// Match on the longest possible context path prefix
if (log.isTraceEnabled())
log.trace(" Trying the longest context path prefix");
Context context = null;
String mapuri = uri;
//最精确uri匹配原则
while (true) {
context = (Context) findChild(mapuri);
if (context != null)
break;
//定义最后一个 '/'
int slash = mapuri.lastIndexOf('/');
if (slash < 0)
break;
mapuri = mapuri.substring(0, slash);
}
// If no Context matches, select the default Context
if (context == null) {
if (log.isTraceEnabled())
log.trace(" Trying the default context");
//默认Context
context = (Context) findChild("");
}
// Complain if no Context has been selected
if (context == null) {
log.error(sm.getString("standardHost.mappingError", uri));
return (null);
}
// Return the mapped Context (if any)
if (log.isDebugEnabled())
log.debug(" Mapped to context '" + context.getPath() + "'");
return (context);
}
init()
负责初始化Host,主要完成以下几个步骤:
public void init() {
if (initialized)
return;
initialized = true;
// already registered.
if (getParent() == null) {
try {
// Register with the Engine
ObjectName serviceName = new ObjectName(domain + ":type=Engine");
HostConfig deployer = new HostConfig();
addLifecycleListener(deployer);
if (mserver.isRegistered(serviceName)) {
if (log.isDebugEnabled())
log.debug("Registering " + serviceName
+ " with the Engine");
mserver.invoke(serviceName, "addChild",
new Object[] { this },
new String[] { "org.apache.catalina.Container" });
}
} catch (Exception ex) {
log.error("Host registering failed!", ex);
}
}
if (oname == null) {
// not registered in JMX yet - standalone mode
try {
StandardEngine engine = (StandardEngine) parent;
domain = engine.getName();
if (log.isDebugEnabled())
log.debug("Register host " + getName() + " with domain "
+ domain);
oname = new ObjectName(domain + ":type=Host,host="
+ this.getName());
controller = oname;
Registry.getRegistry(null, null).registerComponent(this, oname,
null);
} catch (Throwable t) {
log.error("Host registering failed!", t);
}
}
}
start()
负责启动Host,主要完成以下几个步骤:
/**
* Start this host.
*
* @exception LifecycleException
* if this component detects a fatal error that prevents it
* from being started
*/
public synchronized void start() throws LifecycleException {
if (started) {
return;
}
if (!initialized)
init();
// Look for a realm - that may have been configured earlier.
// If the realm is added after context - it'll set itself.
if (realm == null) {
ObjectName realmName = null;
try {
realmName = new ObjectName(domain + ":type=Realm,host="
+ getName());
if (mserver.isRegistered(realmName)) {
mserver.invoke(realmName, "init", new Object[] {},
new String[] {});
}
} catch (Throwable t) {
log.debug("No realm for this host " + realmName);
}
}
// Set error report valve
if ((errorReportValveClass != null)
&& (!errorReportValveClass.equals(""))) {
try {
boolean found = false;
if (errorReportValveObjectName != null) {
ObjectName[] names = ((StandardPipeline) pipeline)
.getValveObjectNames();
for (int i = 0; !found && i < names.length; i++)
if (errorReportValveObjectName.equals(names[i]))
found = true;
}
if (!found) {
Valve valve = (Valve) Class.forName(errorReportValveClass)
.newInstance();
addValve(valve);
errorReportValveObjectName = ((ValveBase) valve)
.getObjectName();
}
} catch (Throwable t) {
log.error(sm.getString(
"standardHost.invalidErrorReportValveClass",
errorReportValveClass), t);
}
}
if (log.isDebugEnabled()) {
if (xmlValidation)
log.debug(sm.getString("standardHost.validationEnabled"));
else
log.debug(sm.getString("standardHost.validationDisabled"));
}
super.start();
}
stop()
负责停止Host,使用基类中的stop()方法
destroy()
负责销毁Host,清理资源占用,主要有以下几个步骤:
public void destroy() throws Exception {
// destroy our child containers, if any
Container children[] = findChildren();
super.destroy();
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof StandardContext)
((StandardContext) children[i]).destroy();
}
}
MemoryLeakTrackingListener
该类的是用来基类Context类加载的,不同的Context可能由不同的类加载器。
Host是tomcat中定义用来管理Context的容器,StandardHost是Host的标准实现,完成对Context的管理,接收父容器Engine传递过来的请求信息,然后根据URI选择合适的Context处理请求,Host还维护在基路径下面的所有的webapp,为他们生成Context。通过类加载的特性来隔离不同Context在应用层面上面的数据安全,不同Context直接不能直接访问。
一直都在迷茫,不知道想要的是什么