当前位置:   article > 正文

跟着springboot的内嵌jetty走进servlet_org.eclipse.jetty.server.nio.selectchannelconnecto

org.eclipse.jetty.server.nio.selectchannelconnector

版本:spring-boot-1.5.17.RELEASE.jar,jetty-servlet-9.4.41.v20210516.jar
springboot启动刷新上下文也是走的AbstractApplicationContext细节不再多说,我们直接进入正题,在onRefresh这个环节是springboot接入内嵌web容器的环节。在创建上下文时系统会判断当前是否是web环境,如果是则创建AnnotationConfigEmbeddedWebApplicationContext默认的web上下文。该上下文中的onRefresh环节进行创建内嵌的容器

新版本spring-boot-2.2.1.RELEASE : org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh

@Override
protected void onRefresh() {
	super.onRefresh();
	try {
		createEmbeddedServletContainer();
	}
	catch (Throwable ex) {
		throw new ApplicationContextException("Unable to start embedded container",
				ex);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

创建内嵌的Servlet容器

  1. 获取内嵌的容器工厂EmbeddedServletContainerFactory,假定为jetty环境即JettyEmbeddedServletContainerFactory
  2. 使用工厂方法获取内嵌的servlet容器,入参为_ServletContextInitializer上下文初始化对象列表_
  3. getEmbeddedServletContainer:创建web上下文JettyEmbeddedWebAppContext与EmbeddedWebApplicationContext.getSelfInitializer()中的ServletContextInitializer实现绑定
  4. addHandlerWrappers:如果开启了压缩则创建createGzipHandler句柄包装JettyEmbeddedWebAppContext(也是句柄类型),如果存在serverHeader则创建ServerHeaderHandler句柄包装JettyEmbeddedWebAppContext(也是句柄类型)。默认不压缩也不存在header。即直接返回JettyEmbeddedWebAppContext。
  5. Server.setHandler中将hander句柄添加至管理的beans中(updateBean)
  6. addHandlerWrappers返回的句柄与org.eclipse.jetty.server.Server绑定
  7. 根据server与端口创建JettyEmbeddedServletContainer。构造器中执行初始化initialize。启动Server.start
  8. Server.start通过父类遍历管理的beans并启动start。包含:JettyEmbeddedWebAppContext.start。
  9. 回调父类WebAppContext启动方法doStart。父类ContextHandler无参构造器中创建ServletContext上下文实现Context(ContextHandler内部类)
    beans

获取spring-web自身的ServletContextInitializer列表

org.springframework.boot.web.servlet.ServletContextInitializer

  1. EmbeddedWebApplicationContext.createEmbeddedServletContainer方法获取ServletContextInitializer接口实现列表:getSelfInitializer
  2. EmbeddedWebApplicationContext.selfInitialize中创建ServletContextInitializerBeans
  3. 根据类型ServletContextInitializer从工厂中获取对象列表遍历
  4. 如果是ServletRegistrationBean类型以Servlet类型为key添加至initializers
  5. 如果是FilterRegistrationBean类型,获取对象的Filter属性并以Filter类型添加至initializers
  6. 如果是DelegatingFilterProxyRegistrationBean类型同Filter相同,source需要通过代理的getTargetBeanName获取
  7. 如果是ServletListenerRegistrationBean类型,获取对象的listener属性并以EventListener类型添加至initializers
  8. 其他按照ServletContextInitializer类型添加至initializers
  9. addAdaptableBeans:根据类型(Servlet、Filter、EventListener)从工厂中获取bean,将bean封装为对应的RegistrationBean并添加至initializers(后面会遍历列表注册bean至ServletContext上下文)
  10. 排序initializers:sortedList

springboot自动注册Servlet至ServletContext

回调spring-web自身ServletContextInitializer.onStartup

EmbeddedWebApplicationContext.selfInitialize遍历ServletContextInitializer回调onStartup方法入参为ServletContext,与Servlet对接

  1. 创建ServletContextInitializerBeans:构造器中根据类型(ServletContextInitializer)从工厂中获取ServletContextInitializer列表
  2. 遍历ServletContextInitializerBeans集合,调用集合元素ServletContextInitializer实现类的onStartup方法,即前面所提到的sorted列表:sortedList,常见的列表(ServletContextInitializer的ServletRegistrationBean实现类型):characterEncodingFilter、hiddenHttpMethodFilter、httpPutFormContentFilter、springSecurityFilterChain、dispatcherServlet、requestContextListener、SessionRepositoryFilter(共享session的Filter)
@Override
public Iterator<ServletContextInitializer> iterator() {
    //sortedList排序后的ServletRegistrationBean列表
	return this.sortedList.iterator();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  1. springmvc的dispatchServlet由DispatcherServletAutoConfiguration配置自动注册,其余由应用本身配置注册或其他自动配置注册
  2. 均为ServletRegistrationBean类型。ServletRegistrationBean类的onStartup方法将绑定的servlet注册至ServletContext上下文并配置
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
	Assert.notNull(this.servlet, "Servlet must not be null");
	String name = getServletName();
	...
	logger.info("Mapping servlet: '" + name + "' to " + this.urlMappings);
    //注册至ServletContext上下文
	Dynamic added = servletContext.addServlet(name, this.servlet);
	if (added == null) {
		logger.info("Servlet " + name + " was not registered "
				+ "(possibly already registered?)");
		return;
	}
    //配置servlet,urlMapping、setLoadOnStartup、setMultipartConfig
	configure(added);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

Jetty内嵌容器工厂获取容器

  1. 获取容器JettyEmbeddedServletContainerFactory.getEmbeddedServletContainer
  2. 创建应用上下文JettyEmbeddedWebAppContext(ServletContextHandler类型),在后面的handle链调用中回调:Server调用handle链的根节点(即第一个handle)
    1. 父类ServletContextHandler执行relinkHandlers,doSetHandler将handler关联至当前handler的_handler属性,并更新注册至当前容器的_beans中,下面均相同逻辑不赘述
    2. 创建SessionHandler并关联至_sessionHandler,doSetHandler,org.eclipse.jetty.server.session.SessionHandler(ManagedObject)
    3. 创建SecurityHandler并关联至_securityHandler,doSetHandler
    4. 创建GzipHandler并关联至_gzipHandler,doSetHandler
    5. 创建ServletHandler并关联至_servletHandler,doSetHandler,org.eclipse.jetty.servlet.ServletHandler(ManagedObject)
  3. 获取端口号port默认为0:org.springframework.boot.context.embedded.AbstractConfigurableEmbeddedServletContainer#getPort
  4. 根据地址与端口创建SocketAddress实例InetSocketAddress
  5. 如果Server对象存在ThreadPool类型入参的构造器则使用jetty9的工厂方法创建Server(org.eclipse.jetty.server.Server);否则使用jetty8(8使用set方法注入线程池);入参为工厂线程池属性。如果连接池为空,构造器中会指定QueuedThreadPool为默认的线程池,最大200线程,最小线程数为8,空闲超时时间60000毫秒(1分钟),线程池名称为qtp前缀+hashcode,线程名称为qtp前缀+线程id
  6. 根据InetSocketAddress与Server创建Connector,jetty8使用org.eclipse.jetty.server.nio.SelectChannelConnector,jetty9使用org.eclipse.jetty.server.ServerConnector
  7. Server绑定connector
  8. 配置WebAppContext上下文configureWebAppContext
  9. web上下文设置contextPath,如果有则设置,默认为根"/"
  10. 如果指定则添加默认servlet:addDefaultServlet
  11. 如果需要注册JspServlet则添加,并添加JasperInitializer bean
  12. 添加字符集
  13. 设置ServletContextInitializerConfiguration入参为Initializer列表
  14. 配置session:configureSession;上下文获取SessionHandler句柄,如果存在超时则设置超时时间,默认为-1;如果指定persistSession需要持久化session则创建默认缓存DefaultSessionCache,为缓存设置文件存储FileSessionDataStore实例。将session缓存绑定至SessionHandler句柄
  15. 为Server设置handler句柄
  16. 如果启用了压缩,使用GzipHandler包装JettyEmbeddedWebAppContext(原始handler)
  17. 如果header包含text,使用ServerHeaderHandler包装handler
  18. _handler更新后更新bean:updateBean,添加至当前Server的_beans中在Server容器start启动时同时启动_beans列表中的管理bean
  19. 如果启用ssl,配置ssl并使用ssl的Connector覆盖原Server的Connector
  20. 获取JettyServerCustomizer列表,为server绑定自定义配置
  21. 如果启用useForwardHeaders,为server绑定ForwardHeadersCustomizer自定义配置
  22. 创建JettyEmbeddedServletContainer实例,入参为Server。如果端口大于0则设置自动启动容器为true。

创建容器JettyEmbeddedServletContainer

  1. 初始化
  2. 启动server:org.eclipse.jetty.server.Server
  3. 调用父类启动方法AbstractLifeCycle.start
  4. 调用子类Server重写的doStart方法
  5. 配置ErrorHandler
  6. 调用父类doStart,遍历ContainerLifecycleLifecycle的_beans,如果bean是managed类型并且没启动调用start方法启动,如果是auto类型,running状态则移除该bean,否则置为managed类型并启动bean
  7. 遍历Server的connectors列表,启动connector,假定为jetty9的ServerConnector
for (Connector connector : _connectors)
{
    try
    {
        connector.start();
    }
    catch(Throwable e)
    {
        mex.add(e);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

服务器连接器ServerConnector

创建ServerConnector

  1. 根据工厂acceptors数量、selector数量创建连接器
  2. 调用父类构造器AbstractConnector
  3. 将server添加至ContainerLifecycle中的beans,类型为UNMANAGED
  4. 将_executor添加至ContainerLifecycle中的beans,类型为:如果已经running则为UNMANAGED,否则为AUTO类型,如果不是Lifecycle类型则类型为POJO
  5. _scheduler注册至beans同_executor逻辑
  6. _byteBufferPool(默认为ArrayByteBufferPool类型)注册至beans同_executor逻辑
  7. 如果acceptors处理数量指定数量小于0,取1与(4与核心数量除以8之间的最小值)两者中的最大值
  8. 根据acceptor数量创建线程数组_acceptors
  9. 创建新的Selector管理器ServerConnectorManager,根据executor、scheduler、selectors数量
  10. 添加_manager至beans,类型为Managed
  11. 为Connector设置host、port

启动ServerConnector

  1. 调用父类start方法回调子类doStart方法
  2. AbstractNetworkConnector父类回调子类open方法,调用父类doStart方法
  3. 如果_acceptChannel为空创建,打开ServerSocketChannel通道绑定地址端口,设置_acceptChannel阻塞为true
  4. 添加_acceptChannel至beans,类型为managed
  5. 继续调用父类AbstractConnector doStart方法
  6. 继续调用父类ContainerLifecycle doStart方法,即调用新注册进来bean的start方法,如果存在auto类型并且running状态且不是unmanaged类型,是InheritedListener类型则移除bean,否则置为unmanaged类型。否则调用start方法
  7. 根据_acceptors长度创建CountDownLatch监听_stopping
  8. 根据_acceptors长度创建Acceptor,并将Acceptor注册至bean(POJO类型),获取线程池执行Acceptor

执行Acceptor

  1. 如果不是处于accepting并且是running状态,_setAccepting等待通知
  2. 回调ServerConnector连接器accept方法
@Override
public void accept(int acceptorID) throws IOException
{
    ServerSocketChannel serverChannel = _acceptChannel;
    if (serverChannel != null && serverChannel.isOpen())
    {
        SocketChannel channel = serverChannel.accept();
        accepted(channel);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  1. accept打开channel并设置为非阻塞类型
  2. 设置socket的SocketOptions.TCP_NODELAY属性打开
  3. SelectorManager选择管理器ServerConnectorManager监听服务器通道accept(channel)
//SelectorManager监听通道
public void accept(SelectableChannel channel, Object attachment) {
    ManagedSelector selector = this.chooseSelector();
    Objects.requireNonNull(selector);
    //将ServerSocketChannel封装为Accept提交至updates,等待消费
    selector.submit(new Accept(selector, channel, attachment));
}
//SelectorManager容器管理初始化
protected SelectorManager(Executor executor, Scheduler scheduler, int selectors) {
    this._selectorIndex = new AtomicInteger();
    this._acceptListeners = new ArrayList();
    this._connectTimeout = 15000L;
    if (selectors <= 0) {
        //选择器默认数量
        //如果线程池是SizedThreadPool类型:为cpu/2与线程池最大线程数/16之间的最小值
        //否则cpu/2
        selectors = defaultSelectors(executor);
    }

    this.executor = executor;
    this.scheduler = scheduler;
    this._selectors = new ManagedSelector[selectors];
    //选择索引算法为index递增对长度取余即轮询方法
    this._selectorIndexUpdate = (index) -> {
        return (index + 1) % this._selectors.length;
    };
}
//容器管理的bean会在初始化管理器之后,启动管理选择器ManagedSelector,也是通过容器启动
protected void doStart() throws Exception {
    this._lease = ThreadPoolBudget.leaseFrom(this.getExecutor(), this, this._selectors.length);

    for(int i = 0; i < this._selectors.length; ++i) {
        ManagedSelector selector = this.newSelector(i);
        this._selectors[i] = selector;
        this.addBean(selector);
    }

    super.doStart();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  1. 选择ManagedSelector容器管理的Selector,提交Accept至_updates(此时attachment为null),如果选择器_selecting为ture则选择当前选择器并唤醒选择器Selector的select阻塞
//ManagedSelector提交监听的Accept对象至队列ArrayDeque
public void submit(ManagedSelector.SelectorUpdate update) {
...
    Selector selector = null;
    synchronized(this) {
        this._updates.offer(update);
        //processUpdates处理之后将_selecting置为true开始唤醒selector的select阻塞
        if (this._selecting) {
            selector = this._selector;
            this._selecting = false;
        }
    }
    if (selector != null) {
        ...
        //唤醒selector select阻塞
        selector.wakeup();
    }
}
//容器初始化时启动bean
protected void doStart() throws Exception {
    super.doStart();
    //调用选择管理器newSelector方法创建打开选择器Selector
    _selector = _selectorManager.newSelector();
    // The producer used by the strategies will never
    // be idle (either produces a task or blocks).
    // The normal strategy obtains the produced task, schedules
    // a new thread to produce more, runs the task and then exits.
    //策略:EatWhatYouKill,通常为从不idle空闲,要么生产task,要么阻塞
    _selectorManager.execute(_strategy::produce);
    // Set started only if we really are started
    Start start = new Start();
    submit(start);
    start._started.await();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  1. ServerConnectorManager容器管理启动时,初始化创建ManagedSelector,ManagedSelector构造器中调用_selectorManager打开Selector,容器管理的doStart中执行EatWhatYouKill策略的produce生产方法,即SelectorProducer

选择器生产者SelectorProducer

EatWhatYouKill不断的调用SelectorProducer执行生产方法返回的任务

processSelected

  1. 获取已存在的SelectionKey(channel注册至selector上时返回的SelectionKey,attachment为SocketChannelEndPoint)
  2. 如果SelectionKey.attachment对象是ManagedSelector.Selectable类型返回task
  3. 回调attachment的onSelected方法,即SocketChannelEndPoint.onSelected,调用父类的ChannelEndPoint.onSelected
  4. 根据SelectionKey的操作类型返回读(_runFillable)、写(_runCompleteWrite)或读写(_runCompleteWriteFillable)双工的入任务
  5. 执行Callback回调任务,例如:ReadCallback回调succeeded,调用连接的onFillable方法,假定为HttpConnection,连接读取数据
  6. 如果是isConnectable则processConnect
  7. 如果是EndPoint则关闭EndPoint

processUpdates

将_updates队列中的SelectorUpdate数据封装的channel注册至指定的selector,并将当前channel与SelectionKey、Selector封装为相应的EndPoint对象(例如:SocketChannelEndPoint),将EndPoint绑定至SelectionKey的attachment

  1. 处理updates队列
  2. 将updates队列转移至updateable队列
  3. 遍历_updateable调用Start的update方法,设置ManagedSelector.this.started为true
  4. Start._started执行countdown
  5. 如果_updates不为空则唤醒selector(同Accept类型消息处理逻辑)
  6. 处理updates队列(Accept类型消息)
  7. 调用Accept的update方法,将Accept绑定的channel注册至当前选择的Selector,返回的SelectionKey的attachment设置为后面创建的EndPoint
  8. 调用_selectorManager执行当前Accept,即提交任务至线程池
  9. 创建EndPoint:选择管理器_selectorManager将当前服务器channel及SelectionKey封装为相应的EndPoint(例如:Selectable、isConnectable、EndPoint类型)绑定至SelectionKey
  10. 创建Connection:例如:HttpConnection
  11. 打开SocketChannelEndPoint.onOpen
  12. 将endPoint添加至连接器的_endPoints
  13. 打开连接器onOpened
  14. 将ReadCallback注册至endPoint的_fillInterest
  15. 遍历监听器_acceptListeners回调onAccept方法
  16. 清空_updateable
  17. 如果_updates为空则设置_selecting标识为true,表示正在选择,并唤醒selector,即通知selector的select方法阻塞消费

updateKeys

  1. 如果SelectionKey的attachment是Selectable类型,则更新SelectionKey

select

  1. 执行生产者的select选择方法,执行Selector的select方法
  2. 阻塞在selector的select方法中等待数据到达
  3. 如果存在数据则将selectedKeys绑定至_keys
  4. 将_keys列表的迭代器赋值至_cursor游标等待processSelected消费游标中的数据
  5. 如果selector已关闭返回false不再继续消费

HttpConnection连接

  1. org.eclipse.jetty.server.HttpConnection#onFillable读取数据
  2. org.eclipse.jetty.server.HttpConnection#fillRequestBuffer填充request的堆外内存buffer
  3. org.eclipse.jetty.server.HttpConnection#parseRequestBuffer解析requestBuffer,解析器:HttpParser
  4. org.eclipse.jetty.server.HttpChannel#HttpChannel通道构建时,同时创建org.eclipse.jetty.server.Request,org.eclipse.jetty.server.Response
  5. org.eclipse.jetty.server.HttpChannelOverHttp->org.eclipse.jetty.server.HttpChannel#handle通道事件channel event,如果不能handle事件继续读取,如果可以则执行handle
  6. HttpChannelOverHttp处理事件:handle(),调用父类HttpChannel.handle
  7. 根据Action类型处理事件,例如:org.eclipse.jetty.server.HttpChannelState.Action#DISPATCH事件转发请求,org.eclipse.jetty.server.HttpChannelState.Action#READ_PRODUCE事件读取Channel数据至org.eclipse.jetty.server.Request等
  8. 遍历监听器列表回调监听器accept方法入参为Request对象
  9. org.eclipse.jetty.server.HttpChannel#getServer获取Server,org.eclipse.jetty.server.Server#handle处理当前通道,假定为异步请求事件
  10. org.eclipse.jetty.server.Server#handleAsync处理HttpChannel通道
  11. org.eclipse.jetty.server.Server#handleAsync解析event(org.eclipse.jetty.server.Request#getHttpChannelState-》org.eclipse.jetty.server.HttpChannelState#getAsyncContextEvent)获取HttpServletRequest、HttpServletResponse、HttpChannel通道的Request、target资源路径,调用org.eclipse.jetty.server.handler.HandlerWrapper#handle,回调handler:org.eclipse.jetty.server.Handler#handle。同步org.eclipse.jetty.server.Server#handle入参是jetty封装的Request/Response,异步org.eclipse.jetty.server.Server#handleAsync入参是实现了Servlet HttpServletRequest/HttpServletResponse
  12. org.eclipse.jetty.server.AsyncContextEvent#AsyncContextEvent(在请求异步起动时创建org.eclipse.jetty.server.Request#startAsync()),javax.servlet.AsyncEvent#getSuppliedRequest获取的请求就是org.eclipse.jetty.server.Request或者启动AsyncContextEvent时传入的ServletRequest请求
public void handleAsync(HttpChannel channel) throws IOException, ServletException
{
    final HttpChannelState state = channel.getRequest().getHttpChannelState();
    final AsyncContextEvent event = state.getAsyncContextEvent();

    final Request baseRequest=channel.getRequest();
    final String path=event.getPath();

    if (path!=null)
    {
        // this is a dispatch with a path
        ServletContext context=event.getServletContext();
        String query=baseRequest.getQueryString();        baseRequest.setURIPathQuery(URIUtil.addEncodedPaths(context==null?null:URIUtil.encodePath(context.getContextPath()), path));
        HttpURI uri = baseRequest.getHttpURI();
        baseRequest.setPathInfo(uri.getDecodedPath());
        if (uri.getQuery()!=null)
            baseRequest.mergeQueryParameters(query,uri.getQuery(), true); //we have to assume dispatch path and query are UTF8
    }
    final String target=baseRequest.getPathInfo();
    final HttpServletRequest request=(HttpServletRequest)event.getSuppliedRequest();
    final HttpServletResponse response=(HttpServletResponse)event.getSuppliedResponse();
	...
    handle(target, baseRequest, request, response);
	...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

handle处理

  1. handle链例如:JettyEmbeddedWebAppContext->ServletContextHandler->SessionHandler->SecurityHandler->ServletHandler
  2. 调用handle链,第一个handle是前面讲到的:JettyEmbeddedWebAppContext,Server容器启动时回调handle的WebAppContext.doStart方法
  3. 调用ServletContextHandler.doStart方法->父类ContextHandler调用startContext方法-》父类org.eclipse.jetty.server.handler.AbstractHandlerContainer#getChildHandlerByClass获取子节点(ScopedHandler类型)
  4. org.eclipse.jetty.servlet.ServletHandler由ContainerLifecycle管理启动doStart,doStart中执行ServletHandle初始化方法
  5. ServletHandler.doStart执行
  6. 更新org.eclipse.jetty.servlet.FilterMapping:org.eclipse.jetty.servlet.ServletHandler#updateNameMappings,更新filterNameMapping、servletNameMapping
  7. 更新updateMappings,如果contextHandler不为空并且已经启动,则执行initialize初始化方法
    1. 执行org.eclipse.jetty.servlet.FilterHolder.start方法
    2. . 执行FilterHolder.initialize方法
    3. 遍历org.eclipse.jetty.servlet.ServletHolder列表->执行ServletHolder.start方法->执行doStart方法
    4. 执行org.eclipse.jetty.servlet.ServletHolder.initailize方法
    5. 如果_initOnStartup则执行initServlet方法,即执行servlet的init方法
    6. 获取Holder beans,遍历执行start、initialize方法
  8. 调用handle链,第一个handle是前面讲到的:JettyEmbeddedWebAppContext,其他的handle节点,例如:ScopedHandler句柄处理,handle方法调用doHandle方法-》org.eclipse.jetty.server.handler.ContextHandler#doHandle方法-》调用org.eclipse.jetty.servlet.ServletHandler#doHandle方法
    1. 执行org.eclipse.jetty.servlet.ServletHolder#prepare方法:如果处于running状态并且servlet为null且servlet class不为null,则初始化servlet:org.eclipse.jetty.servlet.ServletHolder#initServlet-》javax.servlet.Servlet#init
    2. 如果过滤器链不为空调用过滤链,执行javax.servlet.FilterChain#doFilter方法
    3. 否则调用org.eclipse.jetty.servlet.ServletHolder#handle方法:执行servlet的javax.servlet.Servlet#service方法
  9. springboot与jetty对接:org.springframework.boot.context.embedded.jetty.JettyEmbeddedWebAppContext,上下文在springboot获取内嵌Servlet容器时注册至Server(也是handle链中的一个节点);JettyEmbeddedServletContainerFactory.getEmbeddedServletContainer

Servlet注册完成等待处理业务请求

  1. DispatcherServlet,派发请求:dispatch()
  2. 预处理句柄回调:org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle-》org.springframework.web.servlet.HandlerInterceptor#preHandle
  3. 执行句柄处理业务逻辑

总结

  1. 整体可以看到jetty容器为我们做了很多事情,端口的监听已经服务的线程池,网络io处理。而servlet则是我们的应用控制器,处理请求和响应(图片摘自Head First Servlet and JSP)
    图片摘自Head First Servlet and JSP

Servlet

servlet(server applet)是web应用的一套接口标准,用于web应用的数据交换

  1. 容器将http协议请求数据转换为ServletRequest请求数据
  2. servlet转发请求至业务逻辑处理数据
  3. 响应ServletResponse
  4. 容器将ServletResponse转换为http协议响应数据
  5. 响应客户端

状态机

后面再补充图片

/*
 * The state of the request processing lifecycle.
 * <pre>
 *       BLOCKING <----> COMPLETING ---> COMPLETED
 *       ^  |  ^            ^
 *      /   |   \           |
 *     |    |    DISPATCH   |
 *     |    |    ^  ^       |
 *     |    v   /   |       |
 *     |  ASYNC -------> COMPLETE
 *     |    |       |       ^
 *     |    v       |       |
 *     |  EXPIRE    |       |
 *      \   |      /        |
 *       \  v     /         |
 *       EXPIRING ----------+
 * </pre>
 */
private enum RequestState


/*
 * The state of the HttpChannel,used to control the overall lifecycle.
 * <pre>
 *     IDLE <-----> HANDLING ----> WAITING
 *       |                 ^       /
 *       |                  \     /
 *       v                   \   v
 *    UPGRADED               WOKEN
 * </pre>
 */
public enum State
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

链路简述

  1. client -> send ServletRequest -> encode -> http data
  2. decode -> ServletRequest -> init -> servlet do filter chain -> servlet handle process -> servlet service process -> servlet do filter chain -> ServletResponse -> encode -> http data
  3. client decode -> ServletResponse -> client response
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/518304
推荐阅读
相关标签
  

闽ICP备14008679号