How tomcat works 读书笔记十三 Host和Engine(一)

2015-01-27 06:04:56 · 作者: · 浏览: 17

Host

Host是Context的父容器。如果想在一个tomcat上部署多个context就需要使用Host了。上下文容器的父容器是主机,但是可能有一些其它实现,没有必要的时候也可以忽略。不过在实践中,即使是一个Context,我们也使用了Host,为什么?后面我们再说。
Host是个接口,里面有个map方法比较重要
    /**
     * Return the Context that would be used to process the specified
     * host-relative request URI, if any; otherwise return null.
     *
     * @param uri Request URI to be mapped
     */
    public Context map(String uri);
根据url来返回一个Context。
Host的标准实现是StandardHost
构造函数,不解释
    public StandardHost() {
        super();
        pipeline.setBasic(new StandardHostValve());
    }
StandardHost并没有invoke方法,它需要调用ContainerBase的invoke方法。
    //ContainerBase.java
    public void invoke(Request request, Response response)throws IOException, ServletException {
        pipeline.invoke(request, response);        
    }
另外StandardHostValve这个基础阀会调用StandardHost的map方法获得一个context容器。
    public void invoke(Request request, Response response,
                       ValveContext valveContext)
        throws IOException, ServletException {
    ....
        StandardHost host = (StandardHost) getContainer();
    //这里调用的是ContainerBase的map方法 最终会调用StandardHost的map方法(两个map方法没有关系 没有//复写 参数都不一样)
        Context context = (Context) host.map(request, true);   
    ....
    }

StandHostMapper

在ContainerBase的start中有如下的代码

   addDefaultMapper(this.mapperClass);
看ConntainerBase

   ?ContainerBase.java
    protected void addDefaultMapper(String mapperClass) {
    ......
        // Instantiate and add a default Mapper
            Class
   clazz = Class.forName(mapperClass);
            Mapper mapper = (Mapper) clazz.newInstance();
            mapper.setProtocol("http");
            addMapper(mapper);
    ......
    }

这里我又一个小问题,为什么ContainerBase的start中的
addDefaultMapper(this.mapperClass);
调用的是子类中的addDefaultMapper呢?
StandardHost.java
    protected void addDefaultMapper(String mapperClass) {
       // 参数默认为 "org.apache.catalina.core.StandardHostMapper";
        super.addDefaultMapper(this.mapperClass);    
    }

StandardHost的start方法在结尾的时候会调用父类的start方法。

注意:Tomcat4 中的 standardContext 使用了不同的方法来创建一个默认映射器。它的 start 方法中并没有调用 super.start()。相反 Standardcontext 的start 方法调用 addDefaultMapper 来传递 mapperClass 变量。

StandardHostMapper的map方法就是调用StandardHost的map方法。
 public Container map(Request request, boolean update) {
...
    String uri = ((HttpRequest) request).getDecodedRequestURI();
        Context context = host.map(uri);
...
        return (context);
    }
在得到上下对象的时候需要一个往返过程,map 方法介绍两个参数,该方法是在 ContainerBase 中的。然后 ContainerBase 类又在它的子对象中查找合适的映射器并调用它的 map 方法。

StandardHostValve

这是Host的基础阀,什么时候注入的?大家自己想。

StandardHostValve这个基础阀会调用StandardHost的map方法获得一个context容器。
    public void invoke(Request request, Response response,
                       ValveContext valveContext)
        throws IOException, ServletException {
    ....
        StandardHost host = (StandardHost) getContainer();
    //这里调用的是ContainerBase的map方法 最终会调用StandardHost的map方法(两个map方法没有关系 没有//复写 参数都不一样)
        Context context = (Context) host.map(request, true);   
    ....
    HttpServletRequest hreq = (HttpServletRequest) request.getRequest();
        String sessionId = hreq.getRequestedSessionId();
        if (sessionId != null) {
            Manager manager = context.getManager();
            if (manager != null) {
                Session session = manager.findSession(sessionId);
                if ((session != null) && session.isValid())
                    session.access();                 //修改session的最后访问时间
            }
        }
      context.invoke(request, response);          //最后调用context的invoke
    }

为什么必须要有一个Host容器

想想我们之前的SimpleConextConfig,它的作用是将context的configured设置为true,为什么不在context里直接设置?参见观察者模式。
在ConextConfig的标