Tomcat中容器是什么以及容器与容器之间的数量关系。
Tomcat容器到底是什么
学java有一小段时间了,一直使用Tomcat,也知道Tomcat是一个大的Servlet容器,里面还有许多子容器,容器之间都是相互嵌套的。也看过一下接收Tomcat的文章,都是一幅图,图中有好多个框框相互嵌套,表示容器与容器之间的相互嵌套,也没什么说明,把我看得云里雾里的。所以要想了解的更多必须自己探索一下。
现在把自己学到的一点点知识记下来,以免忘记了。
都说Tomcat是一个容器,那么这个容器到底是什么东西,因为说它是一个容器我还是觉得有点抽象,而我看了很多文章都没看到有人说。所以,我想知道Tomcat的本质。脑袋有点转不过弯来,写到这里才发现既然Tomcat是用java写的那它的容器的本质应该就是java类啦。
在开始探索之前我就知道Tomcat中有Server、Service、Engine、Host.....等容器。这些容器与容器之间相互嵌套。既然这些容器的本质就是实实在在的java类(容器就是java类,已经够具体了,这样我才能理解,因为我天天写java类 ^v^ ),那这些不同的容器分别使用什么样的java类来描述的呢???我点是我想要知道的。
经过一番探索,知道这些容器都是有生命周期的java类,他们都继承了共同的接口 Lifecycle 。所以Lifecycle就是这些容器这些java类的顶层接口了。下面是我画的继承体系图。
图一:图片保存下来看吧,博客园的图片编辑无语,改天好好研究一下怎么让他弹出来再改。
通过图中的类名就可以知道哪些类是表示Server,哪些是表示Service哪些是。。。。。。
Tomcat中的这些容器都是有生命周期的容器,那么它的类肯定就有声明周期方法了。先看看顶层接口 Lifecycle ,这个接口里面主要定义了一些生命周期的方法。所以,继承自这个接口的所有容器都有生命周期。
图二:
init()方法:初始化容器组件,它必须在启动容器之前调用。它会创建许多对象。
start():启动容器,比如启动一个Server。
stop():停止执行
destroy():销毁这个容器。
Server容器:一个StandardServer类实例就表示一个Server容器
Service容器:一个StandardService类实例就表示一个Service容器
Engine容器:一个StandardEngine类实例就表示一个Engine容器。
Host容器:一个StandardHost类实例就表示一个Host容器。
Context容器:一个StandardContext类实例就表示一个Context容器。
Wrapper容器:一个StandardWrapper类实例就表示一个Wrapper容器。
以上一共有六种类型的容器,从上到下嵌套,也就是Server容器里面有Service容器,Service容器里面有Engine容器。。。。。。这就是这些容器之间的嵌套关系。
需要注意的是,这些容器之间存在父子关系,但是他们对应的java类之间却不是父子关系。由图一可以看出来。
父容器与子容器之间的数量关系
这些父容器和子容器之间有什么样的数量关系呢???
一个Server容器可以有多个Service容器
/** * The set of Services associated with this Server.用一个数组来保存子容器的引用 */ private Service services[] = new Service[0];
一个Service容器只可以有一个子容器。
/** * The Container associated with this Service. (In the case of the * org.apache.catalina.startup.Embedded subclass, this holds the most * recently added Engine.)
它不是用一个数组来保存子容器的引用的。所以直接的子容器只有一个。 */ protected Container container = null;
这里用Container来表示子容器,根据图一可以看出,Container是Engine、Host、Context、Wrapper 接口的父接口,所以Service容器下面的子容器可能是Engine、Host、Context、Wrapper。但是我觉得一般情况下Service的子容器都是Engine容器吧。
一个Engine容器里面可以有多个 Host 容器
/** * Add a child Container, only if the proposed child is an implementation * of Host. * * @param child Child container to be added */ @Override public void addChild(Container child) { if (!(child instanceof Host))//这里说明Engine的子容器只能是Host throw new IllegalArgumentException (sm.getString("standardEngine.notHost")); super.addChild(child); }
一个Host容器里可以有多个 Context 容器。
/** * Add a child Container, only if the proposed child is an implementation * of Context. * * @param child Child container to be added */ @Override public void addChild(Container child) { child.addLifecycleListener(new MemoryLeakTrackingListener()); if (!(child instanceof Context))//这里说明Host容器的子容器只能是Context容器 throw new IllegalArgumentException (sm.getString("standardHost.notContext")); super.addChild(child); }
一个Host容器中可以有多个Wrapper容器。
/** * Add a child Container, only if the proposed child is an implementation * of Wrapper. * * @param child Child container to be added * * @exception IllegalArgumentException if the proposed container is * not an implementation of Wrapper */ @Override public void addChild(Container child) { // Global JspServlet Wrapper oldJspServlet = null; if (!(child instanceof Wrapper)) {//这里说明Context容器的子容器只能是Wrapper容器。 throw new IllegalArgumentException (sm.getString("standardContext.notWrapper")); } //这里删除了部分代码 }
Wrapper容器下面不允许再有子容器。Wrapper容器是最底层的容器。如果添加子容器的话会抛出异常。
/** * Refuse to add a child Container, because Wrappers are the lowest level * of the Container hierarchy. * * @param child Child container to be added */ @Override public void addChild(Container child) { throw new IllegalStateException (sm.getString("standardWrapper.notChild")); }
服务器接收到请求信息后如何传到我们编写的HttpServlet的呢??如果是SpringMVC的话会先到DispatcherServlet再到Controller,而DispatcherServlet也是HttpServlet的一个间接子类。在下一篇文章Tomcat是如何将请求一步步传递到我们编写的HttpServlet类中的