版本:spring-boot-2.2.1.RELEASE.jar,tomcat-embed-core-9.0.27.jar,jetty:9.4.22.v20191022�
WebServer生命周期
- Spring web应用上下文刷新时(org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh),创建org.springframework.boot.web.server.WebServer
- Spring web应用上下文刷新完成时(org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#finishRefresh),启动org.springframework.boot.web.server.WebServer
- 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�
- 创建上下文JettyEmbeddedWebAppContext�
- 创建server:org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory#createServer
- 配置web应用上下文:org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory#configureWebAppContext
- 为server设置handler:org.eclipse.jetty.server.handler.HandlerWrapper#setHandler
- 按需配置ssl:org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory#customizeSsl
- 按需配置server:org.springframework.boot.web.embedded.jetty.JettyServerCustomizer#customize
启动jetty WebServer
org.springframework.boot.web.embedded.jetty.JettyWebServer#start
- 设置server连接器数组:org.eclipse.jetty.server.Server#setConnectors
- 启动server:org.eclipse.jetty.server.Server#doStart
- 启动server管理的bean,例如:JettyEmbeddedWebAppContext
- 回调org.eclipse.jetty.webapp.WebAppContext#doStart,WebAppContext(JettyEmbeddedWebAppContext父类)
- 回调WebAppContext配置pre,configure,post:org.eclipse.jetty.webapp.Configuration
- 延迟初始化Handler:org.springframework.boot.web.embedded.jetty.JettyWebServer#handleDeferredInitialize
- 启动连接器:org.eclipse.jetty.server.Connector,启动server时也会启动连接器,但是连接器默认情况下为空数组,主要留给自定义业务场景扩展使用,例如:在创建server时就设置好连接器
handler优先级
org.eclipse.jetty.servlet.ServletContextHandler#relinkHandlers
默认优先级如下,背景(配置了serverHeader与压缩)
handler链:JettyHandlerWrappers.ServerHeaderHandler->GzipHandler->JettyEmbeddedWebAppContext->SessionHandler->ConstraintSecurityHandler�->JettyEmbeddedServletHandler�
handler执行链路
架构图
server的每个组件(server容器管理的bean)均可插拔,自定义组装自己的服务器容器,生命周期通过Server父类管理:org.eclipse.jetty.util.component.ContainerLifeCycle
Tomcat
配置web上下文
org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#prepareContext
- 创建上下文:org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedContext
- 创建Pipeline:org.apache.catalina.core.StandardPipeline#StandardPipeline(org.apache.catalina.Container)
- container�:org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedContext
- basic�:org.apache.catalina.core.StandardEngineValve#StandardEngineValve,如果存在basic oldValve则停止,将新的basic Valve设置在管道尾巴节点
- 按需配置default,jsp servlet
- 将context�添加至Host child
- 为context设置生命周期监听器:org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#contextLifecycleListeners
- 遍历org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#contextValves添加至context pipeline
- 为context设置ErrorPage�
- 配置session:org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#configureSession
- 回调上下文自定义配置:org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer#customize
创建tomcat WebServer
org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#getWebServer
- 创建Tomcat:org.apache.catalina.startup.Tomcat#Tomcat
- 创建Connector:org.apache.catalina.connector.Connector#Connector(java.lang.String)
- 创建ProtocolHandler�:org.apache.coyote.http11.Http11NioProtocol
- 调用父类启动协议:org.apache.coyote.AbstractProtocol#start
- 启动EndPoint:org.apache.tomcat.util.net.NioEndpoint->org.apache.tomcat.util.net.NioEndpoint#startInternal
- 启动selector轮训器:org.apache.tomcat.util.net.NioEndpoint.Poller#Poller
- 处理数据:org.apache.tomcat.util.net.NioEndpoint.Poller#processKey,例如:读数据=org.apache.tomcat.util.net.AbstractEndpoint#processSocket(socketWrapper, SocketEvent.OPEN_READ, true�)
- 创建Socket处理器SocketProcessorBase�:org.apache.tomcat.util.net.NioEndpoint#createSocketProcessor
- 获取handler处理数据:org.apache.tomcat.util.net.AbstractEndpoint#getHandler-》org.apache.coyote.AbstractProtocol.ConnectionHandler#process
- 获取Processor处理数据:org.apache.coyote.http11.Http11Processor-》org.apache.coyote.AbstractProcessorLight#process-》org.apache.coyote.http11.Http11Processor#service
- 获取适配器处理数据:org.apache.coyote.AbstractProcessor#getAdapter-》org.apache.catalina.connector.CoyoteAdapter#service
- 解析request请求之后调用connector�->service->container->pipeline处理数据:org.apache.catalina.connector.CoyoteAdapter#service-》org.apache.catalina.connector.CoyoteAdapter#postParseRequest�
- 创建Server:org.apache.catalina.core.StandardServer#StandardServer
- 创建Service:org.apache.catalina.core.StandardService
- 配置连接器:org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#customizeConnector
- 创建Engine:org.apache.catalina.core.StandardEngine#StandardEngine
- 创建Pipeline:org.apache.catalina.core.StandardPipeline#StandardPipeline(org.apache.catalina.Container)
- container�:org.apache.catalina.core.StandardEngine
- basic�:org.apache.catalina.core.StandardEngineValve#StandardEngineValve,如果存在basic oldValve则停止,将新的basic Valve设置在管道尾巴节点
- 创建Host:org.apache.catalina.core.StandardHost#StandardHost
- 创建Pipeline
- container�:org.apache.catalina.core.StandardHost
- basic:同Engine
- 创建WebServer:org.springframework.boot.web.embedded.tomcat.TomcatWebServer#TomcatWebServer(org.apache.catalina.startup.Tomcat, boolean)
- 初始化WebServer:org.springframework.boot.web.embedded.tomcat.TomcatWebServer#initialize
启动tomcat WebServer
调用父类方法:org.apache.catalina.util.LifecycleBase#start
- 初始化:org.apache.catalina.util.LifecycleBase#init-》initInternal�
- 启动:org.apache.catalina.util.LifecycleBase#startInternal
- 停止:org.apache.catalina.util.LifecycleBase#stop-》stopInternal�
org.apache.catalina.core.StandardServer#startInternal
- 遍历services�启动Service:org.apache.catalina.core.StandardService#startInternal
- 启动Engine:org.apache.catalina.core.StandardEngine#startInternal
- 如果存在子容器,启动子容器:org.apache.catalina.core.ContainerBase#children
- 启动pipeline:org.apache.catalina.core.StandardPipeline#startInternal
- 设置状态为STARTING�
- 启动Executor�:org.apache.catalina.core.StandardThreadExecutor#startInternal
- 默认线程池配置,min=25,max=200,name前缀=tomcat-exec-�,队列为LinkedBlockingQueue�子类
- 启动连接器:org.apache.catalina.connector.Connector#startInternal
- 启动完成设置状态为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”部分的子流程,入口:
- 解析request请求之后调用connector�->service->container->pipeline处理数据:org.apache.catalina.connector.CoyoteAdapter#service-》org.apache.catalina.connector.CoyoteAdapter#postParseRequest�
架构图
StandardHost child是上下文TomcatEmbeddedContext
总结
- Jetty服务架构更加简洁,且可插拔特性很适合定制一些个性化功能
- Tomcat服务架构相对复杂些,且容器的组件之间存在强依赖。Tomcat的架构中可以看到它支持配置多个host端口,Jetty是不支持的,需要启动多个JettyWebServer支持
- Jetty的Handler设计略复杂,scope抽象的应用场景没有很明显的优势,甚至有些与handle混淆,有些Handler仅实现了scope抽象,handle抽象用不到直接传递至下一个节点。整个handler链有点像是层高为2的跳跃表
- Tomcat的管道设计相对简单,多个不同的管道可以通过特殊的Valve阀门对接,使得串连为一整条完整的链路,更易理解
对于二者没有谁优谁差吧,阅读源码梳理其架构与链路,可以效仿实现来支撑多变的业务需求。比如:过滤漏斗,可以按照不同的业务线组装不同的过滤漏斗,来匹配合适的订单与配送员。每个过滤漏斗可以支持动态插拔过滤器