基础原理

tomcat的总结

2019-01-15  本文已影响10人  简书徐小耳

classLoader

commonLoader:加载的jar可以提供给tomcat本身和其下面各个项目使用
catalinaLoader:加载的jar只能提供给tomcat本身
sharedLoader:加载的jar包可以给各个项目使用
他们三个都是urlclassloader类型

在bootStrap启动期间 将线程上下文的classloader设置为catalinaLoader,
并使用catalinaLoader加载我们的catalina这个类,这就意味着这个类不会被我们项目中使用
然后后期都是调用catalina方法的load和start方法来启动tomcat,此外我们还将catalina的parentClassLoader设置为sharedLoader
这是为了后期设置weappclassloader的父类埋下伏笔

相关名词解释

catalina.home:tomcat产品的安装目录,bin 和 lib 目录被多个tomcat示例公用
catalina.base:是tomcat启动过程中需要读取的各种配置及日志的根目录,其它目录conf、logs、temp、webapps和work 每个Tomcat实例必须拥有其自己独立的备份。
实现在一台机器上运行多个tomcat实例的目的。
主要就是利用catalina.base,因为它是Tomcat启动过程中读取各自配置的根目录
java.io.tmpdir:获取操作系统缓存的临时目录,不同操作系统的缓存临时目录不一样。
user.dir:则是获取当前tomcat容器启动的位置

SystemLogHandler:

startCapture方法:首先从resume(stack)中获取一个captureLog对象,如果该stack为空则new一个captureLog对象然后从logs(threadLocal)获取stack<caputure>对象,如果为空则创建一个
stopCapture方法:从threadlocal获取stack<caputure>,然后弹出一个CaptureLog 然后写出期间的打印信息
重置CaptureLog存入reuse。
这个SystemLogHanlder,可以收集一段代码内的打印信息,然后统一输出且不影响性能。

appBase和docBase的区别

 <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
<Context path="" docBase="D:\WebContent" sessionCookiePath="/" sessionCookieName="JSESSIONID" />

appBase:

1.appBase是host的属性,其会自动部署appbase指定的目录的项目

docBase

1.docBase是context的属性,指定这个项目的路径(绝对或相对路径)
2.访问路径我们可以通过path指定

外置的Tomcat的启动过程:

一、bootStrap的静态代码块和初始化:

1.静态代码块:主要就是设置catalina.home和catalina.base,其中获取了user.dir 作为上述2个参数未设置时候的备选方案
2.init方法:初始化三个主要的classloader,设置线程上下文的classloader为catalinaLoader生成catalina对象,并将sharedLoader设置为其parentClassLoader

二、调用catalina的load方法

1.初始化工作时候的temp目录-java.io.tmpdir
2.初始化jndi相关的目录
3.创建Digester对象,并使用该对象解析server.xml文件,最终创建Server对象
4.设置server的属性,catalina,catalinaHome和catalinaBase
5.优化system.out和system.error
6.调用server的init方法

三、调用catalina的start方法

1.server的start方法调用
2.如果需要使用钩子则注册一个CatalinaShutdownHook,该钩子会在触发的时候调用catalina的stop方法
,该方法会先删除钩子(因为有可能不是钩子线程调用的stop方法,这样会导致stop调用两次)然后调用server的stop和destory方法。
3.然后调用await和stop方法
4.await方法主要就是根据通过循环判断标识位来判断是否需要结束tomcat或者通过socket监听关闭端口来判断

内置的Tomcat启动过程

一、创建WebServer(内部包含tomcat类,所以这个webServer类似于Facade)

1.创建tomcat类。该类主要是服务于内置或者测试的starter,包含我们基础配置信息,也是用来启动我们的server服务,并且可以添加container的类。
2.设置tomcat的baseDir
3.设置connector,默认协议是Http11NioProtocol类
4.创建一个standardserver,设置catalina.home和catalina.base
5.创建一个standardService,将connector和service互相绑定。
6.调整connector属性,比如端口,还有就是如果我们配置了地址,则协议需要绑定该地址,还有就是给connector
设置uriEncoding,ssl。还有是给协议设置compression。
7.我们也可以通过实现TomcatConnectorCustomizer接口来优化connector或者其内部协议,比如修改adpter或者endpoint
8.当然还有这个TomcatContextCustomizer接口 我们可以优化我们的context
9.上述的两个customizer,我们可以写个BeanPostProcessor,在TomcatServletWebServerFactory初始化之后,调用其add方法添加
10.将被自定义修改后的connector和service中的connector进行对比,如果对象被替换了 就将新的connector加入到service中否则就不用添加
11.禁止host自动部署,在设置engine的是设置了该engine的默认的host为localhost和realm
12.配置engine,首先设置backGroupProcessorDelay时长,这个会启动一个线程每隔一段时间执行后台任务
13.给engine设置valve
14.我们还可以给该service添加我们额外写的connector
15.设置我们context=TomcatEmbeddedContext,设置name和path,displayName,指定docBase
16.添加lifeCycleListeners和parentClassloader,设置webApploader(我们的webappclassLoader的创建者),以及webappclassLoader的类型TomcatEmbeddedWebappClassLoader
17.将webApploader的加载模式设置为true,这就代表我们的这边webappclassLoader采用的是双亲加载模式
18.注册DefaultServlet,将tomcatStarter和context绑定,配置context的valve,修改我们的context
19.最终将tomcat和port包装成tomcatWebServer返回,在tomcatWebServer的构造函数中好友初始化方法
20.该初始化方法主要是:启动tomcat的container,但是会删除connector这样就可以避免connector也被启动,启动一个后台线程每隔一段时间去检测是否关闭标识。

二、启动webServer

1.添加我们上述被删除的connector
2.启动我们的connector

tomcat启动过程就是 调用Server的init方法和start方法,所以我们着重分析这两个方法

一、server的init:

1.standardserver的init方法

2.service的init方法

3.engine的初始化(少了host,context,wrapper的初始化,他们的初始化都是在各自start的时候先进行进行的)

4.host的初始化

5.context的初始化

6.wrapper的初始化

7.connector的初始化

8.protocolHandler的初始化

  1. Nioendpoint的初始化-实际是调用bind方法

二、server的start:

1.server的start方法

2.service的start方法

  1. engine的start

启动realm

  1. host的start方法
  1. context的start方法
  1. wrapper的start方法

7.connector的start方法

8.protocolHandler的start方法

  1. Nioendpoint的start方法

三、tomcat接受处理请求的全流程

-一、Acceptor线程携带endpoint,不断的循环获取socketChannel

-二、将socketChannel包装成Niochannel交给poller线程

-三、Poller线程的run方法-将后续获取到的事件(链接事件)交给SocketProcessorBase处理

-四、SocketProcessorBase的处理流程

  • 五、Processor的service方法逻辑
  • 六、然后将在第五步得到request和response交给Adapter(CoyoteAdapter),调用其service方法处理
  • 七、最终一层层调用到我们的standardWrapperValve的invoke方法

server.xml文件的各个标签的意义

我们的engine标签会配置一个默认的host
名称一般都是localhost,当我们用localhost去请求的时候
我们本地的系统有hosts配置文件可以将我们的localhost解析为实际的ip
默认都是127.0.0.1,当然我们也可以配置localhost1等127.0.0.1

MANIFEST

一般编写MANIFEST.MF文件只需要用到Manifest-Version(MF文件版本号)
、Main-Class(包含main方法的类)、Class-Path(执行这个jar包时的ClassPath,第三方依赖)
比如下面:
Manifest-Version: 1.0
Main-Class: test.Main
Class-Path: ./ ./lib/commons-collections-3.2.jar ./lib/commons-dbcp-1.2.2.jar ./lib/commons-lang-2.3.jar ./lib/commons-logging-1.1.jar

Tomcat中的backlog参数

在linux 2.2以前,backlog大小包括了半连接状态和全连接状态两种队列大小。
linux 2.2以后,分离为两个backlog来分别限制半连接SYN_RCVD状态的未完成连接队列大小
跟全连接ESTABLISHED状态的已完成连接队列大小。
当服务端接受到客户端的syn请求后放入syns的队列中,然后服务端回复syn+ack,等客户端收到ack后 再回复ack给服务端
则服务的就把sync中的半连接放入到accpet queue。一般backlog=完全队列
我们完全队列大小取值=min(backlog,somaxconn)
我们半完全队列大小=
table_entries = min(min(somaxconn,backlog),tcp_max_syn_backlog)
roundup_pow_of_two(table_entries + 1)
roundup_pow_of_two表示取最近的2的n次方的值,举例来说:假设somaxconn为128,backlog值为50,tcp_max_syn_backlog值为4096,则第一步计算出来的为50,
然后roundup_pow_of_two(50 + 1),找到比51大的2的n次方的数为64,所以最终半连接队列的长度是64。

connector容易混淆的名词解释

acceptorThreadCount:代表从socket的完全队列获取socket连接的线程数,其socket连接交给poller
pollerThreadCount:将该socket注册到selector上面,然后捕捉到后续的读写事件交给worker线程处理
maxThreads:则是指worker线程--真正去处理这些socket请求的线程个数
acceptCount: 代表acceptor线程从tcp完全队列里面取connection的限制(因为acceptorCount限制了队列大小)
maxConnections:每当获取到一个socket就代表得到一个connection,然后该connection只有在完成或者某些异常情况下才释放
,从这个角度来说如果不限制connection我们不停的拿socket处理也是不行的,这就是从java层面控制

Tomcat的reload机制

reload方法的主要逻辑

上一篇 下一篇

猜你喜欢

热点阅读