zoukankan      html  css  js  c++  java
  • springboot源码之内嵌tomcat

    springboot版本:2.2.2

    Springboot启动,SpringApplication.run方法中,createApplicationContext方法创建一个工厂:AnnotationConfigEmbeddedWebApplicationContext之后,调用applicationContext的refresh方法,方法中其父类EmbeddedWebApplicationContext的onRefresh方法在调用父类的onRefresh之后,再调用 createEmbeddedServletContainer,从Spring工厂中找到EmbeddedServletContainerFactory的实例,(注:其实这是个TomcatEmbeddedServletContainerFactory的注册是在EmbeddedServletContainerAutoConfiguration中,而这个autoConfiguration是spring-boot-autoconfigure包中spring.factories中***.***.**EnableAutoConfiguration的一个值,之所以返回的是Tomcat的Factory而不是Jetty或者Undertow是因为后两者需要导入需要的jar包)并调用factory的getEmbeddedServletContainer方法(传入ServletContextInitializer作为参数),new 一个Tomcat,set一个new 的Connector,传入Http11NioProtocol作为参数,说明springboot内嵌的tomcat用的nio,getService方法初始化一个StandardServer并为server添加一个StandardService,为service添加一个connector。getHost方法初始化一个StandardEngine,放到service中,又new 一个StandardHost放到engine中,prepareContext方法中,new 一个TomcatEmbeddedContext,放到host中。(注意这里的server-service-engine-host-context,以及后面说到的wrapper,在new的时候都会同时new一个standard****valve放到其pipeline属性中,以便以后链式的处理request和response)。最后new 一个tomcatEmbeddedServletContainer返回,在构造方法中有initialize,其中调用this.tomcat.start(),启tomcat,server.start()---service.start()--->protocolHandler.start()--->endpoint.start()。

    NioEndPoint.start中,bindWithCleanup--->bind方法中,serverSock = ServerSocketChannel.open()是生成一个ServerSocketChannel;serverSock.socket().bind(addr,getAcceptCount())是把ServerSocketChannel绑定到端口上,bind之后startInternal中,初始化一个Poller和一个Acceptor两个线程,其中Acceptor是管理TCP握手建立连接的,其run方法中endpoint.serverSocketAccept()其实是调用刚才的ServerSocketChannel.accept(),生成一个socketChannel;而endpoint.setSocketOptions方法先把socketChannel封装一下,接着调用了poller.register,点进去看,再封装成了PollerEvent,通过addEvent方法放到events中,而PollerEvent的run方法中有socket.getIOChannel().register方法,点进去看,其实就是把刚才生成的socketChannel注册到poller的selector上。而poller线程调用poller的run方法,每次循环开始的时候都会把events中的PollerEvent取出,执行run方法。也就是实际上把socketChannel给注册了,然后遍历selector上的key,调用processSocket方法,封装成一个实现了runnable的SocketProcessorBase放到线程池中,其run方法中有getHandler().process(socketWrapper, event)--->processor.process(wrapper, status)--->service(socketWrapper--->getAdapter().service(request, response)--->connector.getService().getContainer().getPipeline().getFirst().invoke(request, response)--->service的container是engine,pipeline的first是null,所以会调用默认的StandardEngineValve,取出request里面的host,调用host的pipeline链中 first.getNext()[next是StandardHostValve]的invoke,调用StandardContextValve的invoke,从request中取出Wrapper,调用StandardWrapperValve的invoke方法,从host中取出filter,形成filterChain,把servlet(DispatcherServlet)放进去,然后是filterChain.dofilter+dispatherServlet.dispatch,下面就是SpringMVC的东西了。

    未解决:dispatherServlet是怎么被放到request中,然后取出来的?可能和service.start中的mapperListener.start有关?

     对比tomcat和netty的nio框架的异同:

    相同点:都是对Java nio的封装

    不同点:netty的两个group都可以是多个线程,fatherGroup可以绑定多个端口。而tomcat对应fatherGroup的是Acceptor,单线程while循环处理握手,因为只绑定了一个端口,这个和netty差不太多,一个端口对应一个线程;而对应childGroup的是poller,也是单线程遍历selector,也就是一个线程处理多个tcp连接的读和写,记得1.5.几的springboot用的还是poller数组,多个线程轮流分配channel。不过select这时候的cpu占用并不是很高,而后面对运算要求高的springMVC里面用户自己写的逻辑的处理,是放在线程池中的,这样看来,也是可行的。

  • 相关阅读:
    随机发牌 代码
    网络传输 buf 封装 示例代码
    简易数据库实现 UNIX环境高级编程(APUE)第二十章 A Database Library
    状态机学习(六)解析JSON2
    又一篇四则运算代码
    c++ stl源码剖析学习笔记(三)容器 vector
    c++ stl源码剖析学习笔记(二)iterator
    Linux系统编程(16)——正则表达式入门
    Linux系统编程(15)——shell脚本语法
    Linux系统编程(14)——shell常用命令
  • 原文地址:https://www.cnblogs.com/chuliang/p/9818894.html
Copyright © 2011-2022 走看看