StandardHost分析-tomcat6.x源码阅读

2013-10-04

StandardHost是什么

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中一些重要的属性

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

一直都在迷茫,不知道想要的是什么

你可能感兴趣的:(StandardHost分析-tomcat6.x源码阅读)