server---service----engine----host-----context---wrapper---servlet
StandardServer---StandardService----StandartEngine----StandardHost----TomcatEmbeddedContext----StandardWrapper----DispatcherServlet
tomcat是一个io(nio)框架,是去网络连接里读取数据,然后一路流动到servlet中的
先看怎样读取数据:
EmbeddedWebApplicationContext在refresh()中的onRefresh()方法中,会调用createEmbeddedServletContainer()方法,先是生成tomcat,connector,Server,Service,Engine等
,然后生成TomcatEmbeddedServletContainer,在其构造方法中,有initialize()方法,会调用this.tomcat.start();方法中先检测server,connector这些,再调用server的start方法,这个
server是standardServer,(继承LifecycleBase的,实际逻辑都在startInternal方法中),start是调用下面所有的service的start,其实只有一个service,StandardService的start方法中,
1、Engine.start(先不说)
2、executor.start() 这个是线程池的启动
3、mapperListener.start() 这个很重要,以后的request是在这里获取DispatcherServlet
4、connector.start() 这个很重要,是nio启动的逻辑。里面显示protocalHandler的start,再就是NioEndPoint的start---startInternal(这些属性的装配先不说),
然后启动两个主要的组件:poller和acceptor,poller是NioEndPoint的内部类,实现了runnable接口,run方法内部的逻辑是经典的nio逻辑,
select注册在selector上面(怎么注册进来的下面说)所有的连接(Acceptor)的数据,交给线程池去处理。Poller的run方法里,
processKey(sk, attachment)->processSocket,把socketWrapper放到实现了runnable接口的SocketProcessorBase中,放到线程池里处理。SocketProcessorBase的run方法中核心
方法是getHandler().process(socketWrapper, event),调用processor.process(wrapper, status)方法,调用service(socketWrapper)方法,调用getAdapter().service(request, response)
方法,调用connector.getService().getContainer().getPipeline().getFirst().invoke(request, response),在pipeline中开始数据流动。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,除了后面的
异常处理,这里是tomcat中,对request和response责任链的最后一步。再往下,就应该研究DispatcherServlet是怎样反射调用controller方法,配置参数,并处理返回结果的。
filterChain方法是调用internalDoFilter(),进来先判断当前进行到filter数组的哪一个位置,如果在数组内,执行filter的dofilter方法,如果在数组外,说明filter都执行完了,这时候并不直接返回,而是执行
servlet的service方法,这就是为什么我们自己写filter要调用filterChain.dofilter方法,这样的话,又递归进入internalDoFilter(),再判断是不是在数组内。如果不递归调用filterChain.dofilter,那么会往下走,
直接return了,之后的filter和servlet都不会调用。而递归调用的结果是让pos这个位置变量往下移动,直到=n,就不会进入if(pos<n),而绕过return,跳到servlet里面。

request的host属性中,children一直向下走,到wrapper的时候,会有两个wrapper,一个defaultWrapper,一个dispatcherServletWrapper。但是拦截器链中,往下一步走并不是一定是去children中取子容器,
从StandardContextValve中取出wrapper,就是从request的mappingData这个属性中取出wrapper,所以会直接取到dispatcherServletWrapper。而dispatcherServletWrapper的赋值,是在CoyoteAdapter
第337行,postParseSuccess = postParseRequest(req, request, res, response)------679行,connector.getService().getMapper().map(serverName, decodedURI, version, request.getMappingData());
把service中的mapper中的属性,一个个的赋值给request的mappingData属性,第1111行,mappingData.wrapper = contextVersion.defaultWrapper.object,这里“=”后面就是dispatcher的wrapper,
至于contextVersion.defaultWrapper.object这属性为什么直接就是dispatcherServletWrapper,是筛选的时候,检测wrapper中的servlet所匹配的路径,(动态匹配?根据url匹配?)
Q2:所有的filter都是FilterRegistrationBean注册的?是怎么注册的?

springboot源码之(内嵌tomcat)的更多相关文章

  1. 精尽Spring Boot源码分析 - 内嵌Tomcat容器的实现

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  2. 查看和指定SpringBoot内嵌Tomcat的版本

    查看当前使用的Tomcat版本号 Maven Repository中查看 比如我们需要查Spring Boot 2.1.4-RELEASE的内嵌Tomcat版本, 可以打开链接: https://mv ...

  3. SpringBoot内嵌Tomcat开启APR模式(运行环境为Centos7)

    网上查到的一些springboot内嵌的tomcat开启apr的文章,好像使用的springboot版本较老,在SpringBoot 2.0.4.RELEASE中已经行不通了.自己整理了一下,供参考. ...

  4. springboot去除内嵌tomcat和打包在tomcat中运行需要做的步骤

    去除内嵌tomcat和添加jsp依赖 去除内嵌tomcat 在springboot启动依赖中去除内嵌tomcat <dependency> <groupId>org.sprin ...

  5. SpringBoot内置的各种Starter是怎样构建的?--SpringBoot源码(六)

    注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 1 温故而知新 本篇接 外部配置属性值是如何被绑定到XxxProperties类属性上的?--SpringBoot源码(五) 温 ...

  6. SpringBoot内置生命周期事件详解 SpringBoot源码(十)

    SpringBoot中文注释项目Github地址: https://github.com/yuanmabiji/spring-boot-2.1.0.RELEASE 本篇接 SpringBoot事件监听 ...

  7. SpringBoot源码学习系列之嵌入式Servlet容器

    目录 1.博客前言简单介绍 2.定制servlet容器 3.变换servlet容器 4.servlet容器启动原理 SpringBoot源码学习系列之嵌入式Servlet容器启动原理 @ 1.博客前言 ...

  8. SpringBoot的启动流程是怎样的?SpringBoot源码(七)

    注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 1 温故而知新 本篇接 SpringBoot内置的各种Starter是怎样构建的? SpringBoot源码(六) 温故而知新, ...

  9. springboot源码(4)

    我们上3个篇章写了springboot的自动装配.servlet组件的注入以及web容器实现内嵌的原理,现在我们来看springboot启动过程中到底做了些什么,也就是打开我们的run方法: 这里我们 ...

  10. 内嵌tomcat启动速度慢

    项目上最近要把内置的jetty换成tomcat, 来更好的支持servlet 3.0 本来以为换个容器, 几十行代码就好了. 实际上换了tomcat后, 一开始启动tomcat, 非常的慢. jett ...

随机推荐

  1. Cordova入门系列(四)自定义Cordova插件--showToast

    前三篇Cordova入门系列,简单讲解了Cordova,以及如何调用Cordova插件,今天我们讲解一下如何自己做一个插件. 自定义插件,就是自己写一些安卓java代码,然后和js代码以及配置文件,封 ...

  2. python日志模块的使用

    学习一下python的日志模块logging,可以参考如下博客,写得很详细 https://www.cnblogs.com/yyds/p/6901864.html https://www.cnblog ...

  3. 第一次java程序设计作业

    通过JAVA语言的学习,使我对计算机语言有了更加深入的认识和理解.知道了许多JAVA语言与其他语言的区别和特性,及其在我们生活中所发挥的重要作用.最后用一句话表明在学习JAVA语言过程中的感受,那就是 ...

  4. Rails6新增rails db:system:change更换数据库

    rails db:system:change --to=postgresql rails db:system:change --to=mysql rails db:system:change --to ...

  5. python运用PIL制作GIF

    与一.安装Pillow 安装地址:https://pypi.org/project/Pillow/#files 二.准备好图片,并从0开始命名,如下图: (ps:记得存图位置与新建的py文件在同一存放 ...

  6. mysql5.7 timestamp错误:there can be only oneTIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE

    #1293 - Incorrect table definition; there can be only oneTIMESTAMP column with CURRENT_TIMESTAMP in ...

  7. css过渡

    过渡transition是一个复合属性 例子1 .example{ width: 200px; height: 100px; background-color: blanchedalmond; tra ...

  8. Envoy 源码分析--network

    目录 Envoy 源码分析--network address Instance DNS cidr socket Option Socket ListenSocket ConnectionSocket ...

  9. Wincc报表+Listview使用

    listview在Wincc中可以作为显示的控件,对于列表表头的定义如下所示: list的命名,点击属性,在对象名称中对其定义: 有了listview的定义,就可以使用VBS对其表头的定义.具体代码如 ...

  10. 强化学习(六):n-step Bootstrapping

    n-step Bootstrapping n-step 方法将Monte Carlo 与 one-step TD统一起来. n-step 方法作为 eligibility traces 的引入,eli ...