Tomcat and Jetty

版本:spring-boot-2.2.1.RELEASE.jar,tomcat-embed-core-9.0.27.jar,jetty:9.4.22.v20191022�

WebServer生命周期

  1. Spring web应用上下文刷新时(org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh),创建org.springframework.boot.web.server.WebServer
  2. Spring web应用上下文刷新完成时(org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#finishRefresh),启动org.springframework.boot.web.server.WebServer
  3. Spring web应用上下文关闭时(org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#stopAndRelease),关闭释放org.springframework.boot.web.server.WebServer

jetty

配置web上下文

通过编程式配置gzip同样不会生效,会被ServletWebServerFactoryCustomizer�重写,正确方法增加server配置:server.compression.enabled=true�

    @Bean
    public ServletWebServerFactory servletContainer() {
        JettyServletWebServerFactory jetty = new JettyServletWebServerFactory();
        QueuedThreadPool tp = new QueuedThreadPool(200,8, 60000, new BlockingArrayQueue<>(1));
        jetty.setThreadPool(tp);
        jetty.setPort(Integer.parseInt(serverPort.trim()));
        MyJettyServerCustomizer myJettyServerCustomizer = new MyJettyServerCustomizer();
        jetty.addServerCustomizers(myJettyServerCustomizer);
        Compression compression = new Compression();
        compression.setEnabled(true);
        // 注意不生效,会被org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryCustomizer#customize重写
        jetty.setCompression(compression);
        jetty.setServerHeader("my-server-header-value");
        return jetty;
    }

创建jetty WebServer

org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory#getWebServer�

  1. 创建上下文JettyEmbeddedWebAppContext�
  2. 创建server:org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory#createServer
  3. 配置web应用上下文:org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory#configureWebAppContext
  4. 为server设置handler:org.eclipse.jetty.server.handler.HandlerWrapper#setHandler
  5. 按需配置ssl:org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory#customizeSsl
  6. 按需配置server:org.springframework.boot.web.embedded.jetty.JettyServerCustomizer#customize

启动jetty WebServer

org.springframework.boot.web.embedded.jetty.JettyWebServer#start

  1. 设置server连接器数组:org.eclipse.jetty.server.Server#setConnectors
  2. 启动server:org.eclipse.jetty.server.Server#doStart
    1. 启动server管理的bean,例如:JettyEmbeddedWebAppContext
    2. 回调org.eclipse.jetty.webapp.WebAppContext#doStart,WebAppContext(JettyEmbeddedWebAppContext父类)
    3. 回调WebAppContext配置pre,configure,post:org.eclipse.jetty.webapp.Configuration
  3. 延迟初始化Handler:org.springframework.boot.web.embedded.jetty.JettyWebServer#handleDeferredInitialize
  4. 启动连接器:org.eclipse.jetty.server.Connector,启动server时也会启动连接器,但是连接器默认情况下为空数组,主要留给自定义业务场景扩展使用,例如:在创建server时就设置好连接器

handler优先级

org.eclipse.jetty.servlet.ServletContextHandler#relinkHandlers
默认优先级如下,背景(配置了serverHeader与压缩)
handler链:JettyHandlerWrappers.ServerHeaderHandler->GzipHandler->JettyEmbeddedWebAppContext->SessionHandler->ConstraintSecurityHandler�->JettyEmbeddedServletHandler�

handler执行链路
jetty-handle.drawio.png

架构图

server的每个组件(server容器管理的bean)均可插拔,自定义组装自己的服务器容器,生命周期通过Server父类管理:org.eclipse.jetty.util.component.ContainerLifeCycle
jetty-architecture.drawio.png

Tomcat

配置web上下文

org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#prepareContext

  1. 创建上下文:org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedContext
    1. 创建Pipeline:org.apache.catalina.core.StandardPipeline#StandardPipeline(org.apache.catalina.Container)
      1. container�:org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedContext
      2. basic�:org.apache.catalina.core.StandardEngineValve#StandardEngineValve,如果存在basic oldValve则停止,将新的basic Valve设置在管道尾巴节点
  2. 按需配置default,jsp servlet
  3. 将context�添加至Host child
  4. 为context设置生命周期监听器:org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#contextLifecycleListeners
  5. 遍历org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#contextValves添加至context pipeline
  6. 为context设置ErrorPage�
  7. 配置session:org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#configureSession
  8. 回调上下文自定义配置:org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer#customize

创建tomcat WebServer

org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#getWebServer

  1. 创建Tomcat:org.apache.catalina.startup.Tomcat#Tomcat
  2. 创建Connector:org.apache.catalina.connector.Connector#Connector(java.lang.String)
    1. 创建ProtocolHandler�:org.apache.coyote.http11.Http11NioProtocol
    2. 调用父类启动协议:org.apache.coyote.AbstractProtocol#start
    3. 启动EndPoint:org.apache.tomcat.util.net.NioEndpoint->org.apache.tomcat.util.net.NioEndpoint#startInternal
    4. 启动selector轮训器:org.apache.tomcat.util.net.NioEndpoint.Poller#Poller
    5. 处理数据:org.apache.tomcat.util.net.NioEndpoint.Poller#processKey,例如:读数据=org.apache.tomcat.util.net.AbstractEndpoint#processSocket(socketWrapper, SocketEvent.OPEN_READ, true�)
    6. 创建Socket处理器SocketProcessorBase�:org.apache.tomcat.util.net.NioEndpoint#createSocketProcessor
    7. 获取handler处理数据:org.apache.tomcat.util.net.AbstractEndpoint#getHandler-》org.apache.coyote.AbstractProtocol.ConnectionHandler#process
    8. 获取Processor处理数据:org.apache.coyote.http11.Http11Processor-》org.apache.coyote.AbstractProcessorLight#process-》org.apache.coyote.http11.Http11Processor#service
    9. 获取适配器处理数据:org.apache.coyote.AbstractProcessor#getAdapter-》org.apache.catalina.connector.CoyoteAdapter#service
    10. 解析request请求之后调用connector�->service->container->pipeline处理数据:org.apache.catalina.connector.CoyoteAdapter#service-》org.apache.catalina.connector.CoyoteAdapter#postParseRequest�
  3. 创建Server:org.apache.catalina.core.StandardServer#StandardServer
  4. 创建Service:org.apache.catalina.core.StandardService
  5. 配置连接器:org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#customizeConnector
  6. 创建Engine:org.apache.catalina.core.StandardEngine#StandardEngine
    1. 创建Pipeline:org.apache.catalina.core.StandardPipeline#StandardPipeline(org.apache.catalina.Container)
      1. container�:org.apache.catalina.core.StandardEngine
      2. basic�:org.apache.catalina.core.StandardEngineValve#StandardEngineValve,如果存在basic oldValve则停止,将新的basic Valve设置在管道尾巴节点
  7. 创建Host:org.apache.catalina.core.StandardHost#StandardHost
    1. 创建Pipeline
      1. container�:org.apache.catalina.core.StandardHost
      2. basic:同Engine
  8. 创建WebServer:org.springframework.boot.web.embedded.tomcat.TomcatWebServer#TomcatWebServer(org.apache.catalina.startup.Tomcat, boolean)
    1. 初始化WebServer:org.springframework.boot.web.embedded.tomcat.TomcatWebServer#initialize

启动tomcat WebServer

调用父类方法:org.apache.catalina.util.LifecycleBase#start

  1. 初始化:org.apache.catalina.util.LifecycleBase#init-》initInternal�
  2. 启动:org.apache.catalina.util.LifecycleBase#startInternal
  3. 停止:org.apache.catalina.util.LifecycleBase#stop-》stopInternal�

org.apache.catalina.core.StandardServer#startInternal

  1. 遍历services�启动Service:org.apache.catalina.core.StandardService#startInternal
  2. 启动Engine:org.apache.catalina.core.StandardEngine#startInternal
    1. 如果存在子容器,启动子容器:org.apache.catalina.core.ContainerBase#children
    2. 启动pipeline:org.apache.catalina.core.StandardPipeline#startInternal
    3. 设置状态为STARTING�
  3. 启动Executor�:org.apache.catalina.core.StandardThreadExecutor#startInternal
    1. 默认线程池配置,min=25,max=200,name前缀=tomcat-exec-�,队列为LinkedBlockingQueue�子类
  4. 启动连接器:org.apache.catalina.connector.Connector#startInternal
  5. 启动完成设置状态为STARTED:org.apache.catalina.util.LifecycleBase#start

Pipeline优先级

下面的管道优先级由高到低的顺序为:由上到下,由左到右

Engine pipeline

null -> StandardEngineValve[StandardEngine[Tomcat]]

Host pipeline

ErrorReportValve[StandardEngine[Tomcat].StandardHost[localhost]]->StandardHostValve[StandardEngine[Tomcat].StandardHost[localhost]]

Context pipeline

NonLoginAuthenticator[StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[]]->StandardContextValve[StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[]]

DispatcherServlet pipeline

null -> StandardWrapperValve[StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[].StandardWrapper[dispatcherServlet]]

Valve调用链路

管道调用链路入口参考“创建Connector”部分的子流程,入口:

  1. 解析request请求之后调用connector�->service->container->pipeline处理数据:org.apache.catalina.connector.CoyoteAdapter#service-》org.apache.catalina.connector.CoyoteAdapter#postParseRequest�

tomcat-valve-invoke.png

架构图

StandardHost child是上下文TomcatEmbeddedContext
tomcat-architecture.drawio.png

总结

  1. Jetty服务架构更加简洁,且可插拔特性很适合定制一些个性化功能
  2. Tomcat服务架构相对复杂些,且容器的组件之间存在强依赖。Tomcat的架构中可以看到它支持配置多个host端口,Jetty是不支持的,需要启动多个JettyWebServer支持
  3. Jetty的Handler设计略复杂,scope抽象的应用场景没有很明显的优势,甚至有些与handle混淆,有些Handler仅实现了scope抽象,handle抽象用不到直接传递至下一个节点。整个handler链有点像是层高为2的跳跃表
  4. Tomcat的管道设计相对简单,多个不同的管道可以通过特殊的Valve阀门对接,使得串连为一整条完整的链路,更易理解

对于二者没有谁优谁差吧,阅读源码梳理其架构与链路,可以效仿实现来支撑多变的业务需求。比如:过滤漏斗,可以按照不同的业务线组装不同的过滤漏斗,来匹配合适的订单与配送员。每个过滤漏斗可以支持动态插拔过滤器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值