温州开发网站公司,家具做网站,泰安东平县建设局网站,网站建设流程分为哪几个阶段前面很多篇文章都在介绍Context与Wrapper两个容器#xff0c;因为这两个容器确实也比较重要#xff0c;与我们日常开发也息息相关#xff0c;但是Catalina是存在四个容器的#xff0c;这一章就来简单看看Host与Engine这两个容器。
再次展示下Catalina的容器结构#xff0…前面很多篇文章都在介绍Context与Wrapper两个容器因为这两个容器确实也比较重要与我们日常开发也息息相关但是Catalina是存在四个容器的这一章就来简单看看Host与Engine这两个容器。
再次展示下Catalina的容器结构Engine为最顶层的容器父容器与子容器为一对多的关系最底层的容器为Wrapper容器Wrapper容器不再拥有子容器。 Context容器代表一个Web应用Wrapper容器代表Web应用中的一个servlet那么Host与Engine代表啥呢下面通过梳理Engine、Host与Context三者的关系来说明一下。
Host容器与Context容器
一个Tomcat中可以布有多个Web应用也就是可以有多个Context容器实例。至于如何将请求分发到指定Context中则是Host容器的任务了。StandardHost类是Host容器的标准实现。
下面通过一张图来展示下Host容器寻址Context容器的过程 根据uri去匹配Context容器的逻辑是一个循环判断的逻辑代码在StandardHost#map() 方法中下面是精简后的代码
public Context map(String uri) {Context context null;String mapuri uri;while (true) {context (Context) findChild(mapuri);if (context ! null) {break;}int slash mapuri.lastIndexOf(/);if (slash 0) {break;}mapuri mapuri.substring(0, slash);}// 如果没有匹配上就用默认的Contextif (context null) {context (Context) findChild();}return (context);}
假如请求的uri是【/app1/Primitive】那么拿uri去匹配Context的步骤是这样的
先拿“/app1/Primitive”去匹配没有匹配上去掉最后的一个“/”后面的内容uri变为“/app1”,再去匹配匹配上了拿到结果
如果最终也没有匹配上就取默认的Context来用默认Context在children中的key为空字符串。像我们使用SpringBoot开发项目的话项目针对的Context在Host children中的key就为空字符串。
书中源码给了一个以Host为顶级容器的示例我将启动类展示出来感兴趣的可以下源码来自己试试
package ex13.pyrmont.startup;//explain Hostimport ex13.pyrmont.core.SimpleContextConfig;
import org.apache.catalina.*;
import org.apache.catalina.connector.http.HttpConnector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.core.StandardWrapper;
import org.apache.catalina.loader.WebappLoader;public final class Bootstrap1 {public static void main(String[] args) {//invoke: http://localhost:8080/app1/Primitive or http://localhost:8080/app1/ModernSystem.setProperty(catalina.base, System.getProperty(user.dir));Connector connector new HttpConnector();Wrapper wrapper1 new StandardWrapper();wrapper1.setName(Primitive);wrapper1.setServletClass(PrimitiveServlet);Wrapper wrapper2 new StandardWrapper();wrapper2.setName(Modern);wrapper2.setServletClass(ModernServlet);Context context new StandardContext();// StandardContexts start method adds a default mappercontext.setPath(/app1);context.setDocBase(app1);context.addChild(wrapper1);context.addChild(wrapper2);LifecycleListener listener new SimpleContextConfig();((Lifecycle) context).addLifecycleListener(listener);Host host new StandardHost();host.addChild(context);host.setName(localhost);host.setAppBase(webapps);Loader loader new WebappLoader();context.setLoader(loader);// context.addServletMapping(pattern, name);context.addServletMapping(/Primitive, Primitive);context.addServletMapping(/Modern, Modern);connector.setContainer(host);try {connector.initialize();((Lifecycle) connector).start();((Lifecycle) host).start();// make the application wait until we press a key.System.in.read();((Lifecycle) host).stop();} catch (Exception e) {e.printStackTrace();}}
} Engine容器与Host容器
host顾名思义url中的host可以是域名也可以是ip。Host容器对应的也就是url中的host每个Host容器实例都被安排接收其对应的“url中带有相关host的请求”。至于如何将一个请求分发到指定Host容器实例中则是Engine容器的任务了Engine容器是顶层容器它不会再有父容器。StandardEngine类是Engine容器的标准实现。
如果Engine容器作为顶层容器的话连接器则与Engine容器做关联一个请求进来后连接器则会将请求抛入Engine的invoke()方法Engine再将请求给到指定的HostHost再给到指定的ContextContext再给到指定的Wrapper层层流转下来请求就到达了指定的servlet中servlet会对请求进行处理与反馈然后将反馈结果层层上抛最终给到连接器连接器将结果返回给客户端一个请求的寻址与处理流程就完成了。
我们通过一张图来展示下Engine容器寻址Host容器的过程 简单来说就是解析请求url中的host字符串然后拿这个host字符串当做Host实例的name去 子容器map集合 children 中去匹配Host容器实例匹配不上的话就用默认Host默认Host一般为keylocalhost 的这个Host。用SpringBoot开发的项目中就只有一个 key为 localhsot 的Host实例默认Host也是它。
书中源码给了一个以Engine为顶级容器的示例我将启动类展示出来感兴趣的可以下源码来自己试试
package ex13.pyrmont.startup;//Use engineimport ex13.pyrmont.core.SimpleContextConfig;
import org.apache.catalina.*;
import org.apache.catalina.connector.http.HttpConnector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardEngine;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.core.StandardWrapper;
import org.apache.catalina.loader.WebappLoader;public final class Bootstrap2 {public static void main(String[] args) {//invoke: http://localhost:8080/app1/Primitive or http://localhost:8080/app1/ModernSystem.setProperty(catalina.base, System.getProperty(user.dir));Connector connector new HttpConnector();Wrapper wrapper1 new StandardWrapper();wrapper1.setName(Primitive);wrapper1.setServletClass(PrimitiveServlet);Wrapper wrapper2 new StandardWrapper();wrapper2.setName(Modern);wrapper2.setServletClass(ModernServlet);Context context new StandardContext();// StandardContexts start method adds a default mappercontext.setPath(/app1);context.setDocBase(app1);context.addChild(wrapper1);context.addChild(wrapper2);LifecycleListener listener new SimpleContextConfig();((Lifecycle) context).addLifecycleListener(listener);Host host new StandardHost();host.addChild(context);host.setName(localhost);host.setAppBase(webapps);Loader loader new WebappLoader();context.setLoader(loader);// context.addServletMapping(pattern, name);context.addServletMapping(/Primitive, Primitive);context.addServletMapping(/Modern, Modern);Engine engine new StandardEngine();engine.addChild(host);engine.setDefaultHost(localhost);connector.setContainer(engine);try {connector.initialize();((Lifecycle) connector).start();((Lifecycle) engine).start();// make the application wait until we press a key.System.in.read();((Lifecycle) engine).stop();} catch (Exception e) {e.printStackTrace();}}
}
Engine与Host 两个容器的主要内容就是上面这些涉及到的类也是容器老生常谈的几种类容器标准实现类 StandardEngineStandardHost容器Pipeline的基础阀 StandardEngineValveStandardHostValve容器相关的映射器 StandardEngineMapperStandardHostMapper这些映射器在Tomcat4中还存在现在使用的Tomcat版本已经不存在这些映射器了根据请求获取Host、Context的这些逻辑都放在了request对象中来实现了。想看看源码的看看这几个类就行。
本章内容就介绍到这里Engine与Host两个容器的功能与我们的开发工作 关联并不太多我们了解其工作方式即可。 源码分享
https://gitee.com/huo-ming-lu/HowTomcatWorks
这一篇在源码中有两个示例感兴趣的同学可以自己运行看看