StandardHost分析-tomcat6.x源码阅读

摘要:2013-10-04 StandardHost是什么 StandardHost是StandardHost.Host的标准实现,继承自ContainerBase基容器,具备容器的功能和特征,在tomcat的结构层次图中位于Engine容器内部,是Engine的子容器,是Context的父容器,负责管理多个Context,即webapp。Host是虚拟主机,一个Engine下面可以有多个虚拟主机。虚拟

 

StandardHost是什么

StandardHost是StandardHost.Host的标准实现,继承自ContainerBase基容器,具备容器的功能和特征,在tomcat的结构层次图中位于Engine容器内部,是Engine的子容器,是Context的父容器,负责管理多个Context,即webapp。Host是虚拟主机,一个Engine下面可以有多个虚拟主机。虚拟主机主要做的任务就是负责将Engine中传递过来的请求选择一个合适的Context处理,解决的是Context的选择问题,不同Conext之间数据隔离和共享、数据安全问题,负责根据配置文件生成应用程序的Context。

Host
是tomcat中定义的虚拟主机接口,定义了虚拟主机所需要具备的功能,例如应用文件的磁盘路径,Host的的基路径,校验xml配置文件,发布应用。

002UASMrzy7605pjKJv15&690.jpg

ContainerBase
Host继承是基容器具备容器的功能,具有父容器引用,管理子容器和容器中的组件,还有后台任务处理线程。

StandardHostValve
是StandHost的basicvalve,在Host容器pipeline valve链的末端,负责为请求信息选择一个合适的Context处理,控制权转移,控制数据流向。

Host中一些重要的属性

aliases Host的别名列表 aliasesLock 在对aliase操作时需要加锁 appBase Host基路径,tomcat会自动扫描路径下面的应用让后启动 configClass Host配置文件处理器类 contextClass Host的Context实例类,用于生产Context errorReportValveClass 请求错误处理类,例如404,502 childClassLoaders 子容器类加载器,主要是Context使用,使用不同的类加载器,起到安全隔离的作用。

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,主要完成以下几个步骤:

标记已经初始化,注册Host到MBserver

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,主要完成以下几个步骤:

判断是否已经启动 判断是否已经初始化 注册realm到Mbserver中 判断errorReportValveClass类,实例化并添加到pipeline中 调用基类启动器

/** * 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,清理资源占用,主要有以下几个步骤:

调用基类的destroy()方法 遍历子容器,调用子容器destroy()

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直接不能直接访问。