Tomcat外部原理
Tomcat 大家始终都在用,也用了好多年了,然而 Tomcat 到底是啥,外部是咋样的,不晓得~来,我从源码角度,给大家揭开它的面纱~
1. Tomcat架构
这个是tomcat的架构图,专治密集恐惧症患者~~虚线的代表同一多个
- Server:代表一个运行的tomcat实例,蕴含一个或多个service子容器
- Service: 代表tomcat中一组解决申请,提供服务的组件,蕴含多个Connector和一个Container
Connector: 在指定IP、端口、协定下监听客户端申请,创立Request 、Response 给 Engine,从Engine取得响应给客户端。Connector是通过ProtocolHandler 来解决申请的,ProtocolHandler蕴含三个部件:Endpoint、Processor、Adapter
- Endpoint: 解决底层socket 网络连接。Acceptor 监听申请,Handler解决接管到的socket, AsyncTimeout 查看异步Request的超时
- Processor: 将Endpoint 接管到的Socket 封装成Request
- Adapter: 将Request 交给Container 解决
Container: 容器的父接口,用于封装和治理 Servlet,采纳责任链设计模式,蕴含四个组件
- Engine: 可运行的servlet 引擎实例,一个服务中只有一个。次要性能是将申请委托给适当虚拟主机解决。
- Host: Engine的子容器,一个Host代表一个虚拟主机,一个虚拟主机能够部署一个或多个Web App,每个Web App对应一个Context
- Context: 代表Servlet 的Context,是Servlet的根本运行环境,示意web利用自身。它最重要性能是治理外面的servlet
- Wrapper: 示意一个独自的Servlet,是Context的子容器,也是最底层的容器,没有子容器了。治理 Servlet的装载、初始化、执行和资源回收
2. Tomcat源码
咱们来追踪 SpringBoot启动过程,看一下它是怎么创立Tomcat的。
跟到 ServletWebServerApplicationContext#refresh()办法,如图:
点开 createWebServer()办法:
进入TomcatServletWebServerFactory#getWebServer():
一步步来看tomcat的构建过程。
设置运行门路
File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");tomcat.setBaseDir(baseDir.getAbsolutePath());
增加 Connector
Connector connector = new Connector(this.protocol);connector.setThrowOnFailure(true);tomcat.getService().addConnector(connector);
先点getService()进去看下:
public Service getService() { return getServer().findServices()[0];}
再点getServer()看看:
public Server getServer() { if (server != null) { return server; } System.setProperty("catalina.useNaming", "false"); server = new StandardServer(); initBaseDir(); ConfigFileLoader.setSource(new CatalinaBaseConfigurationSource(new File(basedir), null)); server.setPort( -1 ); // server里增加一个名为”tomcat“的service Service service = new StandardService(); service.setName("Tomcat"); server.addService(service); return server;}
tomcat里,先创立server,server设置关联的service,service再增加 connector,跟咱们下面的架构图截然不同。
再来看Host:
tomcat.getHost().setAutoDeploy(false);
点击getHost()进去:
public Host getHost() { Engine engine = getEngine(); if (engine.findChildren().length > 0) { return (Host) engine.findChildren()[0]; } Host host = new StandardHost(); host.setName(hostname); // Engine增加host getEngine().addChild(host); return host;}
能够看到,Host是被当做子容器增加到Engine里的,比照架构图,没骗你吧~~
再点getEngine()进去:
public Engine getEngine() { Service service = getServer().findServices()[0]; if (service.getContainer() != null) { return service.getContainer(); } Engine engine = new StandardEngine(); engine.setName( "Tomcat" ); engine.setDefaultHost(hostname); // engine设置为service的容器 service.setContainer(engine); return engine;}
又能够看到,engine被当做service的容器设置进去了,没有问题。
回到 getWebServer(),看这一行:
configureEngine(tomcat.getEngine());
点击这个办法进去:
private void configureEngine(Engine engine) { engine.setBackgroundProcessorDelay(this.backgroundProcessorDelay); for (Valve valve : this.engineValves) { engine.getPipeline().addValve(valve); }}
engine里有pipeline,pipeline一个个增加valve,串成链。
如同还漏了架构图的两个货色,context和servlet,回到getWebServer() 持续点击:
prepareContext(tomcat.getHost(), initializers);
点击该办法进去,看要害代码:
protected void prepareContext(Host host, ServletContextInitializer[] initializers) { File documentRoot = getValidDocumentRoot(); TomcatEmbeddedContext context = new TomcatEmbeddedContext(); context.setName(getContextPath()); …… if (isRegisterDefaultServlet()) { addDefaultServlet(context); } if (shouldRegisterJspServlet()) { addJspServlet(context); addJasperInitializer(context); } context.addLifecycleListener(new StaticResourceConfigurer(context)); ServletContextInitializer[] initializersToUse = mergeInitializers(initializers); host.addChild(context); configureContext(context, initializersToUse); postProcessContext(context); }
这外面都是设置context的,包含增加默认的servlet,最初context以子容器的模式增加到了host中。中,看图谈话~