1、生命周期及观察者模式重要的接口和类
- Lifecycle生命周期接口:
- 生命周期抽象方法事件字符串
- lifeCycleListener监听器操作方法.
- 获取生命周期状态
- container接口:容器接口,继承生命周期接口。
- 拥有自己独有child和valve的add和remove事件字符串
- containerListener监听器操作抽象方法
- backgroudprocess后台执行线程抽象方法。
- 以及各组件的操作方法。
- containerBase抽象类:container的实现类,也继承了LifecycleMBeanBase。
- 定义了pipoline,
- 四个生命周期方法的internel方法、
- 监听器listener、
- add child的操作,
- 是否添加child就启动的标志等。
- backgroudprocess实现:主要启动cluster、reaml、valve的backgroudprocess。
- containerBase抽象类:container的实现类,也继承了LifecycleMBeanBase。
- lifecycleBase抽象类:
- 成员变量 CopyOnWriteArrayList lifecycleListeners、LifecycleState变量默认为NEW。
- lifecycleListeners监听器操作方法、fireLifecycleEvent发布事件方法、init、start、stop、destory四个生命周期方法,以及加initInternal等需要子类实现的模板方法。
- 生命周期方法里面调用了子类的Internel方法,并在前后setState重新设置状态,setState中还有fireLifecycleListener发布事件方法,其中的event是从state枚举类的属性中获取的。
- 以init方法为例具体的变化为调用initInternal前setState(initializing),调用后setState(initialized)。
- 以start方法为例子。调用前setStste(start_prep),子类实现的startIntenal中调用setState(starting),startIntenal执行完成之后会执行setState(started)。
- 特别需要注意的是,在生命周期方法中,会有状态是否异常的判断,例如start方法已进入就会判断是否已经在start的三种状态中,是则return。或者是new就先调用init。或者是failed就调用stop方法。
- LifecycleMBeanBase抽象类:主要是组成JMX
- tomcat的组件信息需要注册到JMX的MBServer中,这个就是定义组件的MBean父类,
- 实现了initInternal,在其中register组件信息到JMX。
- 实现可destoryInternal,在其中unRegister组件信息。
- LifecycleMBeanBase抽象类:主要是组成JMX
- LifecycleState枚举类:生命周期的状态
- LifecycleListener接口:监听器接口
- engineConfig
- hostConfig
- contextConfig
- EventObject类:事件父类,携带事件源对象的信息
- LifecycleEvent类:事件子类
- ContainerEvent类:容器事件子类
- containerListener接口:容器的监听器接口
- mapperListener接口 详见3.6
1.1 、LifecycleState生命周期的状态
//新建
NEW(false, null),
//初始化中后
INITIALIZING(false, Lifecycle.BEFORE_INIT_EVENT),
INITIALIZED(false, Lifecycle.AFTER_INIT_EVENT),
//启动前中后
STARTING_PREP(false, Lifecycle.BEFORE_START_EVENT),
STARTING(true, Lifecycle.START_EVENT),
STARTED(true, Lifecycle.AFTER_START_EVENT),
//结束前中后
STOPPING_PREP(true, Lifecycle.BEFORE_STOP_EVENT),
STOPPING(false, Lifecycle.STOP_EVENT),
STOPPED(false, Lifecycle.AFTER_STOP_EVENT),
//销毁前中后
DESTROYING(false, Lifecycle.BEFORE_DESTROY_EVENT),
DESTROYED(false, Lifecycle.AFTER_DESTROY_EVENT),
//失败状态
FAILED(false, null);
- mapperListener接口 详见3.6
1.2、实现的设计模式
- 观察者模式:lifecycleListener以及containerListener
- 责任链模式:容器的pipoline及valve和servlet的fliter
- 模板方法模式 :lifecycleBase下的init/start/stop/destory——Internal();
- 门面模式:catalina这个类就是门面模式,操作tomcat的生命周期,通过catalina
- 适配器模式:protocolHandler接口中的adapter,转换request和response的。
1.3、线程周期的四大方法主要实现(ContainerBase中的internel实现)
- initInternel方法
- 在lifecycleMBeanBase方法中有实现,主要是注册JMX的操作
- 子类ContainerBase中有实现。
- 启动一个线程池,核心最大线程默认为1,超时时间是10秒,阻塞队列是LinkedBloclkingQueue。
- StartInternel方法
- ContainerBase中有实现
- 启动cluster和Realm一般不用。
- 用线程池启动所有的子容器(child),得到futureList,循环get()阻塞等待所有子容器执行完毕。
- 启动pipoline。执行责任链中的所有valve
- 转换生命周期state为starting
- 启动后台线程,这个后台线程是定时检查有没有超时的会话。
- ContainerBase中有实现
- StopInternel 方法
- ContainerBase中有实现
- 像是start的反向执行一样
- 停止后台线程
- 设置生命周期state为stopping
- 关闭pipoline
- 关闭子容器,get()阻塞等待所有返回
- 关闭realm和cluster
- ContainerBase中有实现
- DestoryInternel方法
- ContainerBase中有实现
- 销毁realm和cluster
- 销毁pipoline
- removeChild
- 停止后台执行线程
- ContainerBase中有实现
- 后台执行线程相关的方法
- ContainerBase中有实现
- backgroundProcess方法:后台执行线程的具体实现,每个容器都可以有自己的
- threadStart 方法,new Thread()执行后台线程
- ContainerBackgroundProcessor内部类,作为Thread实例化参数。内部需要判断threadDone参数,在执行。先执行本类的backgroundProcess,然后判断子类的BackgroundProcessorDelay参数,小于等于0代表子类不自己执行,就由父类执行。
- ContainerBase中有实现
2、执行流程中的重要的接口和类
- Bootstrap:启动类,包含main函数,是tomcat启动入口。
- catalina:核心类,控制组件的生命周期。
入口时bin目录下的startup目录,window在bin使用./startup.bat可以启动tomcat。里面的命令指
- startup.bat:在改脚本中启动了catalina.bat
- catalina.bat:在该脚本中启动了java类Bootstrap。执行了该类的main函数。
- 接下来的步骤在2.1中
2.1、Bootstrap的启动原理中重要的方法
- bootstrap.init()方法
- initClassLoaders();初始化类记载器。根据配置文件,决定是否create创建 commonLoder、serverLoader、sharedLoder。如果配置文件为空,则返回的是加载当前类的类加载器。一般配置了server和shared都是需要隔离开tomcat和应用使用的类加载器。
- 后续的方法是使用catalinaLoader加载catalina类,并使用反射调用setParentClassLoader方法
- daemon = bootstrap
- daemon.load(args):通过反射调用了catalina中的load方法。
- catalina.load()
- 创建digester,定义engine、host、context、以及生命周期监听器engineCongfig、hostConfig、contextConfig等规则,parse解析server.xml,生成对象树。调用server的生命周期函数init
- catalina.load()
- daemon.start():通过反射调用了catalina中的start方法。
- catalina.start():调用了server的start方法,创建jvm的shutdownHook钩子函数,最后调用await方法(server的TCP连接监听Port,收到shutDown 就执行后面的Stop等)主线程阻塞,阻塞完毕调用生命周期的stop方法和destory方法。
3、server、service、connector各组件的接口和类和方法
- server接口:server组件的接口继承lifecycle接口,有操作JNDI下resource的方法,listener的方法,获取catalina的方法,操作services的方法。
- StandardServer类:继承了lifecycleMBeanBase,实现了Server。四个internel实现都是设置生命周期状态,发布事件,循环调用子容器对应的生命周期函数,在StopInternel中有设置关闭StopAwait,关闭server的TCP监听,不在接收Shutdown命令。
- initInternel方法:
- 向JMX注册StringCache对象和MbeanFactory对象
- 初始化JNDI,GlobalNamingResource.init
- 资源集合添加mainFastResource
- 调用子组件中的init方法
- StartInternel方法:
- 发布start_event事件
- 设置状态为Starting
- 启动JNDI资源GlobalNamingResource.start
- 调用所有子组件的Start方法
- stopInternel方法:
- service接口:service组件的接口,继承lifecycle接口。有连接器管理的接口、有引擎管理的接口
- StandardService类:继承了lifecycleMBeanBase,实现了service接口,四个internel的方法,管理engine和connector的生命周期。
- initInternel方法:
- engine.init初始化引擎
- executor.init初始化业务线程池
- 初始化mapperListener监听器
- connector.init初始化连接器
- StartInternel方法:
- 设置状态为Starting
- 启动引擎engine.start
- 启动业务线程池executor.start
- 启动MapperListener监听器
- 启动connector.start
- initInternel方法:
- StandardService类:继承了lifecycleMBeanBase,实现了service接口,四个internel的方法,管理engine和connector的生命周期。
- connector类:继承了LifecycleMBeanBase,连接器组件,
- 构造方法:接收server.xml 配置中的protocol,由digester创建。构造方法接收到具体的protocol,然后反射创建protocolHandler接口的实现类进行处理
- initInternel方法:
- 调用父类初始化实现
- 初始化适配器对象 adapter = new coyoteAdapter();
- protocolHandler.setAdapter()
- 协议升级的过程
- protocolHandler.init() 初始化协议处理类
- startInternel方法
- 设置状态为Starting
- protocolHandler.start()启动协议处理类
- 成员变量protocolHandler接口。自己的生命周期管理、升级协议方法等。
- adapter接口,适配器,转换request ,response
- executor接口,线程池管理
- AbstractProtocol抽象类,实现了protocolHandler
- 协议处理类,在3.1有详述
3.1、协议类和端点类
什么是协议
简单的说就是传输数据包的格式
协议有两种:AJP、http
什么是端点
网络连接中java使用的哪种网络编程
SocketServer/SocketServerChannel/AIO/jni编程等
这些工作形式称为端点。
端点有三种:NIO、NIO2(AIO)、APR(JNI网络编程,全部调用C语言的类库)
protocolHandler协议处理接口,该接口实现类没有实现标志的生命周期接口。
实现类AbstractProtocol类
- init方法
- jmx注册
- enpoint.init()
- start方法
- endpoint.start()
- 启动后台异步超时线程,timeoutThread
- 属性的设置直接就调用了endpoint的实现
- CreateProcessor:创建具体处理协议的处理器,会保存input和output缓冲区
- 其生命周期方法主要管理enpoint的生命周期
- AbstractHttp11Protocol:createProcessor的实现,创建Http11Processer
- inti方法
- 协议升级
- super.init()
- Http11NioProtocol 对NIO的返回name进行的定义,设置poller的count等。
- Http11Nio2Protocol
- Http11AprProtocol
- inti方法
- AbstractAjpProtocol
- AjpNioProtocol
- AjpNio2Protocol
- AjpAprProtocol
端点类:
AbstractEndpoint
- 内部Handler接口,处理连接。在abstractProtocol的内部类实现。
- 内部成员变量accepterThreadCount 接收线程数量,也就是说有几个线程进行accept操作,默认为1
- 内部成员变量maxConnections,保存accept得到的Socket,默认最大10000
- 内部成员变量acceptCount,back_log的大小,默认为100
- 内部成员变量LimitLatch connectionLimitLatch,内部类sync继承了aqs类,重写了tryAcquireShared方法和tryReleaseShared方法,对automicLong的加减操作,如果increment后大于limit,那么返回-1阻塞。
- 子类NioEndpoint
- 内部成员变量NioSelectorPool,选择器池
- 内部成员变量serverSocketChannel
- 内部bind方法
- ServerSocketChannel.open、bind、configureBlocking(true)
- selectorPool.open();
- 内部startInternel方法:
- 如果excutors为空,重新创建业务线程池
- initializeConnectionLatch:初始化连接限制,如果maxConnections小于0,那么不设置connectionLimitLatch,因为默认为10000,所以将maxConnections作为参数创建LimitLatch
- 创建Poller[2] ,然后作为参数启动线程。
- 初始化limitLatch
- 最后启动 Acceptor[1],后作为参数启动线程。
- 这个方法执行完毕,tomcat就可以accept请求了。
- 内部acceptor,是一个runnable子类
- countUpOrAwaitConnection方法,使用LimitLatch检测是否达到最大连接数,达到就阻塞
- 阻塞时的调用accept,获取SocketChannel
- 获取到的SocketChannel会设置为非阻塞的,然后包装成NioChannel
- 创建一个SocketBufferHandler,在JVM层面给Socket包装的缓存区。这里默认的是使用的堆上内存,可以改成使用直接内存。Niochannel的成员变量
- Niochannel包装了Socket和SocketBufferHandler。
- 使用NioSocketWrapper(SocketWrapperBase是其父类。主要操作读写缓冲区的)包装NioChannel,设置属性和op_read事件
- 创建PollerEvent对象,包装NioSocketWrapper。定义好op_register事件
- 最后放到Poller的队列中。
- 内部PollerEvent,是一个runnable子类
- 该子类中的Run方法定义了Socket注册Read事件到selector中
- 内部Poller,是一个runnable子类,找到可读写的key,dispatch到线程池中处理
- 内部成员变量selector,
- 成员变量synchronizedQueue
队列 - Run方法执行了events()方法,是执行队列中PollerEvent的run,进行注册Read事件
- 先判断wakeUpCounter(addEvent方法的时候会判断wakeUpCounter并进行selector.wakeup唤醒阻塞)的数值,再执行Selector.selectNow/Selector.select(TimeOut默认1秒阻塞),然后还原wakeUpCounter
- keyCount为0,重新执行events();因为是被唤醒的
- keyCount大于0,则执行Selector.selectedkeys方法,找到可读的KEY,执行processKey()这个重要的后续方法
- 最后timeOut(keyCount,hasEvents),遍历键值集,处理读写超时的key,对其执行cancelKey、关闭套接字,关闭通道。如果以下四种状态成立,则不进行上述操作
- (keyCount > 0 || hasEvents),
- nextExpiration存在
- nextExpiration没有超时
- close状态为false
- processKey(),对可用的KEY进行处理的方法
- 如果关闭close直接cancelkey
- key有效且可读可写,先判断SendfileData不为空处理processSendfile()方法
- 其中使用的零拷贝(FileChannel的transferTo方法),首先从socketWrapper中取出FileChannel然后与SocketChannel对接(FD直接的复制)
- transferTo方法
- 首先判断系统是否支持senFile,支持采用这个系统调用
- 然后判断是否支持MMAP
- 最后是普通的读写。
- 为空再处理读写
- 先unreg该key的intrerestOps即感兴趣的事件
- 然后判断Key的读写事件,读写都会调用processSocket方法参数不同op_read/op_write
- processSocket方法
- 对Socket进行处理,首先会在缓存中取一个ScoketProcessorBase出来,这是一个Task,包装socketWrapper(该对象是attachement参数)。dispatch为True(传参就是True),会把该Task放到线程池中去处理。否则当前线程处理。
- (Worker)SocketProcessorBase,worker线程池就是执行这个类,
- 这个类主要处理了协议升级,handShake
- 最后调用了getHandler().process(SocketWrapper,SocketEvent.op_read)
- Handler的实现类是AbstractProtocol内部类ConnectionHandler,
- ConnectionHandler
- private final Map
connections = new ConcurrentHashMap<>();每一个Channle都又一个对应的处理器 - process方法,取Processor,没有初始化, 执行处理器Processor的process方法,state = processor.process(wrapper, status),对返回的State进行判断处理,设置connections,以便第二次进入直接取。
- Processor类下的process方法,在3.2中详解
- private final Map
- ConnectionHandler
- 子类Nio2Endpoint
- 子类AprEndpoint
3.2、Processor接口实现及方法
- Processor
- AbstractProcessorLight:轻量级的实现,只实现了Process方法,其他都是模板方法,在process 方法中调用了核心的方法service模板方法
- AbstractProcessor:存在adapter、asyncStateMachine异步状态机
- 成员变量request以及response,
- 构造方法中实例化request和response
- AjpProcessor
- Http11Processor:
- 成员变量存在Http11缓冲区,主要是对tomcat原生缓冲区进行Http11的解析、以及Http11Parser解析器
- Http11InputBuffer inputBuffer
- 内部存在filter对读数据进行过滤
- 会调用SocketWrapper的read。最后会读取SocketChannel.Read。
- Http11OutputBuffer outputBuffer;
- Http11InputBuffer inputBuffer
- service方法:该方法的作用:转换http头部、验证头部、根据头部设置request信息及安装Filter过滤器、读取数据执行请求、结束请求、还原状态
- 从SocketWrapper中取得读写缓冲区数据,然后进行http解析,最后放到自己的Http11缓冲区中。
- prepareRequest方法
- 读取请求头后,设置请求过滤器。
- InputFilter[] inputFilters = inputBuffer.getFilters();获取到过滤器的library,
- 根据用户请求,将FilterLibrary中的Filter添加的activeFilter中。责任链调用doRead方法,之后读取Wrapper然后读到SocketChannel中的数据。
- getAdapter().service(request, response); 。该方法默认创建HttpServletRequest、HttpServletResponse,并互相关联,和coyote的req\res关联。CoyoteAdapter implements Adapter。
- postParseRequest方法,解析header后执行必要的处理,例如解析uri上get传输的参数,便于传给容器。初始化request的mappingData。
- connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);执行Pipeline进行invoke,在这个地方进入引擎Engine,详细处理过程在4、中详解
- Rreq.getReadListener().onAllDataRead(); 执行ReadListener的事件方法。(3.1异步的时候使用,在数据准备好后在onAllDataRead方法中将业务Task加入线程池执行)
- StreamProcessor
- UpgradeProcessorBase:协议升级相关
- UpgradeProcessorExternal
- UpgradeProcessorInternal
- AbstractProcessor:存在adapter、asyncStateMachine异步状态机
- AbstractProcessorLight:轻量级的实现,只实现了Process方法,其他都是模板方法,在process 方法中调用了核心的方法service模板方法
3.3、request和response
- request:聚合在AbstractProcessor中,connector层使用
- 构造方法
- parameters.setQuery(queryMB);
- parameters.setURLDecoder(urlDecoder);
- 成员变量Parameters Parameters
- 成员变量MessageBytes queryMB
- 成员变量UDecoder urlDecoder
- 构造方法
- response:聚合在AbstractProcessor中,connector层使用
- HttpServletRequest:上面两个会被转换成下面两个,在Engine层被使用
HttpServletResponse:上面两个会被转换成下面两个,Engine层被使用
3.4、枚举类
SocketEvent
这个是Socket的事件,是需要对scoket进行的操作
OPEN_READ:读事件
- OPEN_WRITE:写事件
- STOP:组件被关闭了,Socket需要被close
- TIMEOUT:代表Servelet3.0的异步操作超时了,Socket需要被关闭
- DISCONNECT:连接失败
- ERROR:连接错误
-
SocketState
这个是描述Socket的
OPEN:打开
- CLOSED:关闭
- LONG,:长连接
- ASYNC_END:异步处理完成
- SENDFILE:处于sendFile中
- UPGRADING:协议升级中
- UPGRADED:协议升级结束
-
3.5、 executor执行器原理
executor接口
containerListener接口:容器的监听器接口
engine接口:继承Container接口,
- StandardEngine实现类:继承了ContainerBase抽象类
- 构造方法中设置了pipeline的basic的valve即StandardEngineValve
- initInternal方法:
- getRealm()认证用于校验
- super.initInternel()
- StartInternal方法:
- super.startInternel()
- StandardEngine实现类:继承了ContainerBase抽象类
- Host接口:继承Container接口
- StandardHost实现类:继承了ContainerBase抽象类
- 构造方法中设置了pipeline的basic的valve即StandardHostValve
- StartInternel方法:
- 在pipoline中添加valve(ErrorReportValve)
- StandardHost实现类:继承了ContainerBase抽象类
- ContextBind:绑定解绑类加载器。
- Context接口:继承Container。继承ContextBind。session的管理,wrapper的管理,filter的管理,errorPage的管理
- StandardContext实现类:继承了ContainerBase抽象类。
- initinternel:jndi操作等
- StartInternel:
- 创建work目录、
- 设置webResourceRoot、
- resourcesStart方法启动资源(调用StandardRoot的StartInternel方法)详见4.5、
- setLoader()方法,设置webappLoader类加载器组件,打破双亲委派,隔离context之间的类加载器。详见4.6、
- 启动子容器
- 创建session管理器manager,详见4.7
- getServletContext()获取servlet上下文对象,为空则新建,详见4.8
- StandardContext实现类:继承了ContainerBase抽象类。
- wrapper接口
- StandardWrapper类,也实现了ContainerBase,是一个servlet的包装类,管理servlet的生命周期函数
- allocate()方法,使用线程上下文类加载器加载servlet。并反射生成实例。
- 如果一个Servlet没有被部署在分布式的环境中,一般web.xml中声明的一个Servlet只对应一个实例。放入实例池
- 而如果一个Servlet实现了SingleThreadModel接口,就会被初始化多个实例。
- allocate()方法,使用线程上下文类加载器加载servlet。并反射生成实例。
- StandardWrapper类,也实现了ContainerBase,是一个servlet的包装类,管理servlet的生命周期函数
4.1、pipeline接口
- pipeline接口:责任链,存valve,最后一个valve叫Basic,需要调用到下一个容器。
- StandardPipeline实现pipeline接口,实现了lifeCycleBase抽象类。
4.2、Valve接口
- valve接口:需要被放进pipeline执行的类
- ValveBase:继承LifecycleMBeanBase。
- StandardEngineValve:为StandardEngine容器实现实现默认基本行为的 Valve。
- invoke方法:
- 从request的mappingData拿到host,
- 执行主机的pipeline,host.getPipeline().getFirst().invoke(request, response);
- invoke方法:
- StandardHostValve
- invoke方法:
- 从request的mappingData拿到context。
- context.bind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);将线程上下文类加载器替换为webAppClassLoader类加载器。
- 最后执行Context的pipeline,context.getPipeline().getFirst().invoke(request, response);
- 如果有异常,调用throwable方法,找到errorPage
- 调用了 context.findErrorPage(throwable),处理ErrorPage页并进行返回。
- 如果没有会根据状态码匹配,都没有会写回500异常。
- 我们可以在web.xml文件下根据状态码设置Errorpage.
- invoke方法:
- StandardContextValve
- invoke方法:
- 定义web-inf和meta-inf不可访问,返回404
- 从request的mappingData拿到wrapper。
- wrapper.getPipeline().getFirst().invoke(request, response);执行wrapper中pipeline中的valve。
- invoke方法:
- StandardWrapperValve :servlet的包装
- invoke方法:
- servlet = wrapper.allocate();使用线程上下文类加载器加载servlet。并反射生成实例。
- 如果一个Servlet没有被部署在分布式的环境中,一般web.xml中声明的一个Servlet只对应一个实例。放入实例池
- 而如果一个Servlet实现了SingleThreadModel接口,就会被初始化多个实例。
- ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet); 将servlet作为FilterChannel最后一个节点进行调用。
- ApplicationFilterChain filterChain =
- 配置文件中匹配请求路径的过滤器加入filterChain
- filterChain.doFilter(request.getRequest(),
response.getResponse());执行doFilter,filter 执行完毕之后就会执行FilterChain 中的servlet.service()方法,这之后就是我们所熟知的内容了
- filterChain.doFilter(request.getRequest(),
- servlet = wrapper.allocate();使用线程上下文类加载器加载servlet。并反射生成实例。
- invoke方法:
- StandardEngineValve:为StandardEngine容器实现实现默认基本行为的 Valve。
- ValveBase:继承LifecycleMBeanBase。
4.3 、errorPage
- ErrorPageSupport
- 成员变量private ConcurrentMap
exceptionPages = new ConcurrentHashMap<>(); 异常与errorpage的映射关系 - 成员变量private ConcurrentMap
statusPages = new ConcurrentHashMap<>();errorCode与ErrorPage的关系
- 成员变量private ConcurrentMap
- ErrorPage
4.4 、容器相关的监听器
LifecycleListener接口:监听器接口
- EngineConfig:引擎监听器,启动和关闭事件打印DEBUG事件
- HostConfig:主机监听器,
- lifeCycleEvent发布事件的方法
- Check() 方法,periodic_event周期性事件
- 后台执行线程的周期判断资源文件的lastModified,进行unDeploy或者reDeploy
- beforeStart()方法,before_start_event事件
- 该方法创建目录,AppBaseFile(webapps) 目录以及ConfigBaseFile(conf)目录(copyXml标志位true会将context配置从项目下复制到conf\Catalina\localhost目录下)
- Start()方法,start_event事件
- deployApps()方法,会将项目资源部署加载在StandardRoot下的资源集当中,三种部署方法,还会启动后台线程监听xml和目录是否文件时间戳改变,重新部署
- 一个是在configBase(conf/catalina/host/context.xml)目录下的context配置
- 一个是部署解压好的文件
- 一个是部署WAR包
- ReloadResource。需要重新加载的静态资源。web.xml等
- RedeployResource。需要重新部署的资源。 context.xml ,war等
- load和deploy的区别,load不删除上下文Context,只是重新加载文件。
- deployApps()方法,会将项目资源部署加载在StandardRoot下的资源集当中,三种部署方法,还会启动后台线程监听xml和目录是否文件时间戳改变,重新部署
- stop()方法,stop_event事件
- 移除JMX注册
- Check() 方法,periodic_event周期性事件
- lifeCycleEvent发布事件的方法
- ContextConfig:上下文监听器,
4.5、资源节点
webResourceRoot:资源根节点 继承Lifecycle。对资源节点进行管理
- StandardRoot:继承lifecycleMBeanBase。
- 成员变量:preResources、mainResources、classResources、jarResources、postResources、allResources,资源目录集,这个是在HostConfig中部署时创建并赋值的
- initInternel方法:遍历allResources资源集,调用WebResourceSet的Init方法
- StartInternel方法:
- 创建mainResources主资源
- 遍历启动除ClassResource的allResource,(实际Start启动只是设置了状态)
- 启动classResource之前处理WEB-INF/lib,将其中的jar挂载到web-inf/classes目录下,add到ClassResource资源集中
- StandardRoot:继承lifecycleMBeanBase。
- WebResource:单个Resource资源。单个Class
- WebResourceSet:Resource资源集合,继承Lifecycle。是目录或者jar或者war
- AbstractResourceSet
- AbstractFileResourceSet
- DirResourceSet:目录
- WarResourceSet:war
- JarResourceSet:jar
- AbstractFileResourceSet
- AbstractResourceSet
4.6、tomcat使用的类加载器
- bootStarp类加载器:加载java核心类库
- extension类加载器:加载java扩展类库
- system类加载器:加载$CATALINA_HOME/bin/bootstrap.jar 、$CATALINA_BASE/bin/tomcat-juli.jar、$CATALINA_HOME/bin/commons-daemon.jar
- common:类加载器:加载%catalinaBase%/lib下的jar;
loader :
ClassLoader抽象类
构造方法:默认的parent类加载是systemClassLoader
- ParallelLoaders.isRegistered()判断是否注册,然后才初始化parallelLockMap
- isRegistered方法,在set loaderTypes中找到当前类加载器是否存在
private static final Set<Class<? extends ClassLoader>> loaderTypes =
Collections.newSetFromMap(new WeakHashMap<>());
- isRegistered方法,在set loaderTypes中找到当前类加载器是否存在
- ParallelLoaders.isRegistered()判断是否注册,然后才初始化parallelLockMap
loadCLass方法
- 获取锁,getCLassLoadingLock方法:如果 parallelLockMap不为空,每一个类都新new一个对象锁,否则就使用当前类加载器作为锁,并行处理。
- findLoadedClass():获取虚拟机缓存
- 如果父类加载器不为空,调用父类的loadClass方法,为空,调用findBootstrapClassOrNull使用本地方法中的bootStarp类加载器。
- 如果父类加载器返回的class为空,用自己的FindClass加载该类,
- SecureClassLoader类
- URLClassLoader类:指定类加载路径的类加载器。
- WebappClassLoaderBase:为Web 应用程序创建一个类加载器,加载context中web-inf/classes和web-inf/lib中的类和jar。违背双亲委派机制,优先到localRepositories中查找并加载类,加载的顺序如4.6.2、,JRE基类的一部分类不能被覆盖。
- start方法:
- 从webResourceRoot取到web-inf/classes路径的webResource,添加到localRepositories中。取到web-inf/lib中的jar包,添加到localRepositories中,并添加到jarModificationTimes中监听变化
- 重写loadClass方法:
- 获取锁,getCLassLoadingLock方法:如果 parallelLockMap不为空,每一个类都新new一个对象锁,否则就使用当前类加载器作为锁,并行处理。
- findLoadClass0()方法:检测我们之前放置的本地类缓存,resourceEntry成员变成存放已经加载过的类名与lastModify的映射
- findLoadClass:查询虚拟机缓存
- 获取JSE类的类加载器,加载核心包
- delegate为True或者是servlet规范和tomcat下的一些包,使用Class.forname(ClassName,false,parentClassLoader)
- 使用本类的findClass加载
- delegate为false,使用Class.forname(ClassName,false,parentClassLoader)
- 重写findClass方法
- findClassInternal方法:
- resourceEntries查看是否有存Class,没有新建一个resourceEntry
- 通过获取class文件的字节数组,调用defineClass方法
- findClassInternal方法:
- defineClass方法:根据二进制数组生成Class类
- ParallelWebappClassLoader子类:
- WebappClassLoader子类:
4.6.2、tomcat官方文档,加载顺序原文。
tomcat官方文档,加载顺序原文。Therefore, from the perspective of a web application, class or resource loading looks in the following repositories, in this order:
- Bootstrap classes of your JVM
- /WEB-INF/classes of your web application
- /WEB-INF/lib/*.jar of your web application
- System class loader classes (described above)
- Common class loader classes (described above)
If the web application class loader is configured with
then the order becomes: - Bootstrap classes of your JVM
- System class loader classes (described above)
- Common class loader classes (described above)
- /WEB-INF/classes of your web application
- /WEB-INF/lib/*.jar of your web application
- start方法:
- WebappClassLoaderBase:为Web 应用程序创建一个类加载器,加载context中web-inf/classes和web-inf/lib中的类和jar。违背双亲委派机制,优先到localRepositories中查找并加载类,加载的顺序如4.6.2、,JRE基类的一部分类不能被覆盖。
- URLClassLoader类:指定类加载路径的类加载器。
4.6.2、tomcat 为什么要打破双亲委派机制
- 不同应用程序之间同一个第三方类库的不同版本,应该保证相互隔离
- 不同应用程序之间同一个第三方类库的相同版本,应该共享。
- web 容器自己所依赖的类库应该与应用程序依赖的类库隔离开
- 支持jsp的修改,每个jsp都有自己的类加载器,修改后直接卸载重新创建jsp类记载器
根据以上的四点,tomcat团队的解决方法就是本节开头的第二张图。
4.6.3、打破双亲委派机制的方法
- 重写loadClass方法
- 线程上线文类记载器可以让父加载器委托给子类记载器加载
4.7、session管理器manager
Manager
ServletContext
SocketBufferHandler中包装的Socket缓存区,是否使用直接内存为False改成True。
- maxConnections大小。
- worker线程池大小
6、缓冲区
- Socket原生的读写缓冲区
- NioChannel中聚合的SocketBufferHandler中的readBuffer和WriterBuffer
- Http11Processor中的Http11InputBuffer和Http11OutputBuffer
未解决的问题, linitlatch怎么控制连接大小的