源码解读全文
Tomcat
- 下载源码
- 配置pom文件
- 启动
org.apache.catalina.startup.BootStrap
下的main
方法 JNDI Java Naming and Directory Interface
,在一个中心注册一个东西,只需要配置这个东西的属性参数,即可使用,类似properties
文件的配置
架构
conf下的server.xml配置文件
server
服务器
Listener
GlobalNamingResources
指定一些资源的配置信息,@Resource
,提供了JNDI
的实现Service
,服务,一个服务器可以有多个服务,真正处理服务,不同的服务,端口不同,功能不同
Service
,其中Catalina
用来处理Http
请求
Connector
,连接器,绑定监听的端口,进行接受数据,处理请求Engine
,引擎,服务交给引擎处理
Engine
Realm
,认证配置Host
,主机,域名,一个引擎可以有多个host
接口关系
- 核心组件,都继承了
Lifecycle
,LifecycleBase
,模板方法,定义好步骤,核心步骤留给子类实现
- 初始化
init()
- 启动
start()
- 停止
stop()
- 销毁
destory()
- 当前组件状态
LifecycleState getState()
Container
容器特点
addChild(Container child);
getParent();
拥有父类getPipeline();
拥有管道
Pipeline
管道特点,数据交给引擎后,每流过一层,都要经历每一层容器的管道的所有阀门
getValves();
获取所有阀门,阀门机制,用来进行对数据干预的,AccessLogValve
访问日志的阀门getBasic();
获取基本阀门
Valve
阀门,责任链模式
getNext();
获取下一个void invoke(Request request, Response response)
阀门执行
启动流程
Bootstrap.main
,调用bootstrap.init();
- 解析命令,默认是
start
,String command = "start";
daemon.load(args);
加载命令行参数信息,其中解析server.xml
,并且进行服务器初始化
- 为配置文件的每一个标签创建一个对应的类,封装好标签配置的属性内容
- 通过
NIO - ServerSocketChannel
绑定端口,准备接受数据
daemon.start();
启动服务器,反射调用Catalina
的start
bootstrap.init
- 初始化类加载器
initClassLoaders();
- 加载应用
jar
包- 加载
lib
下的jar
包- 加载自己写的代码
- 加载
Catalina
启动类,Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
- 配置
Catalina
类加载器 catalinaDaemon = startupInstance;
当前Catalina
实例是守护线程
daemon.load(args)
- 实际上,通过反射调用
catalinaDaemon
的load
方法
Method method =
catalinaDaemon.getClass().getMethod(methodName, paramTypes);
- 解析服务器的
server.xml
文件,parseServerXml(true);
- 此时只包括
xml
文件中的内容Server s = getServer();
- 服务器初始化
getServer().init();
parseServerXml
- 加载资源
ConfigFileLoader.setSource(new CatalinaBaseConfigurationSource(Bootstrap.getCatalinaBaseFile(), getConfigFile()));
getConfigFile()
为"conf/server.xml";
- 获取解析器
Digester digester = start ? createStartDigester() : createStopDigester();
- 解析
xml
文件,digester.parse(inputSource);
,通过读取器解析getXMLReader().parse(input);
- 按照层级架构封装成
Catalina
对象
getServer().init()
- 调用父类
LifecycleBase
的模版方法,其中initInternal();
由子类实现 - 调用子标签
GlobalNamingResources JNDI
初始化,globalNamingResources.init();
- 初始化
service
for (Service service : services) {
service.init();
}
daemon.start()
- 反射调用
Catalina
的start
,Method method = catalinaDaemon.getClass().getMethod("start", (Class [])null);
- 服务器启动
getServer().start();
层层启动组件,并且通过父类
LifecycleBase
的模版方法,调用子类真正的启动方法,逻辑与初始化一致
Catalina
启动完成后,调用getServer().await();
,阻塞服务器,接受网络请求,监听8005
的端口- 设置服务器套接字,并进行等待
awaitSocket = new ServerSocket(getPortWithOffset(), 1, InetAddress.getByName(address));
- 服务器进行循环,
socket = serverSocket.accept();
开启网卡端口(跟实际服务的端口不一致),接受net
的scoket
ServerSocket serverSocket = awaitSocket;
StandardServer.startInternal()
globalNamingResources.start();
service.start();
for (Service service : services) {
service.start();
}
service.init()
- 过程中通过
NIO
绑定了端口,准备好socket
- 调用父类
LifecycleBase
的模版方法,其中initInternal();
由子类实现 - 引擎初始化,
engine.init();
- 线程池初始化,
executor.init();
- 监听器初始化,
mapperListener.init();
- 连接器初始化,
connector.init();
engine.init()
- 调用父类
LifecycleBase
的模版方法,其中initInternal();
由子类实现 - 配置
Realm
,getRealm();
connector.init()
- 过程中通过
NIO
绑定了端口,准备好socket
- 调用父类
LifecycleBase
的模版方法,其中initInternal();
由子类实现 - 给协议处理器设置适配器
adapter = new CoyoteAdapter(this); protocolHandler.setAdapter(adapter);
- 协议处理器初始化
protocolHandler.init();
endpoint.init();
端口初始化
endpoint.init()
bindWithCleanup();
绑定端口,其中调用bind();
,底层NIO - ServerSocketChannel
绑定端口
service.start();
engine.start();
executor.start();
mapperListener.start();
connector.start();
engine.start()
- 部署项目
((Lifecycle) cluster).start();
集群启动((Lifecycle) realm).start();
- 找到所有子容器
Host/Context/Wrapper
,封装成StartChild
StartChild
实现了Callable<Void>
,其中call
方法进行了start
,交给线程池执行,实现递归后台
启动所有子容器
((Lifecycle) pipeline).start();
管道启动
host.start
- 获取所有阀门
Valve[] valves = getPipeline().getValves();
,检查所有的阀门
errorValve.equals(valve.getClass().getName())
- 添加
ErrorReportValve
阀门
Context.start()
- 处理工作目录
postWorkDirectory();
- 发送生命周期事件
fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);
ContextConfig
监听到,调用webConfig();
wrapper.setServletClass(servlet.getServletClass());
设置servletClass
,为接受到请求,创建其他servlet
作准备
- 创建启动时加载的servlet
loadOnStartup(findChildren())
,其中调用wrapper.load()
,对servlet
进行加载和初始化
wrapper保存servlet信息,对于MVC中,此时初始化
DispatcherServlet
pipeline.start()
- 设置基础阀门
current = basic;
- 启动所有阀门
过程中进行
init()
初始化,并设置状态值setState(LifecycleState.STARTING);
while (current != null) {
if (current instanceof Lifecycle) {
((Lifecycle) current).start();
}
current = current.getNext();
}
connector.start()
- 协议处理器启动
protocolHandler.start();
,Http1.1 NIO
protocolHandler.start()
- 端点启动
endpoint.start();
- 创建
work
线程,真正处理请求的线程createExecutor();
- 类似
Netty
中的workerGroup
- 默认10个,最多200,队列无边界(Integer.MAX_VALUE),
executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
- 连接限流
initializeConnectionLatch();
connectionLimitLatch = new LimitLatch(getMaxConnections());
,最大8*1024
个连接
- 启动
poller = new Poller();
,并直接单线程启动pollerThread.start();
- 启动接受者线程
startAcceptorThread();
protected void startAcceptorThread() {
acceptor = new Acceptor<>(this);
String threadName = getName() + "-Acceptor";
acceptor.setThreadName(threadName);
Thread t = new Thread(acceptor, threadName);
t.setPriority(getAcceptorThreadPriority());
t.setDaemon(getDaemon());
t.start();
}
Tomcat中的线程
NIO
的处理流程acceptor
Acceptor
- 监听
8080
端口,接受连接socket = endpoint.serverSocketAccept();
serverSock.accept();
,实际上为serverSockChannel.accept()
- 尝试设置
socket/socketChannel
,!endpoint.setSocketOptions(socket)
- 封装
socket
成NioSocketWrapper
- 注册这个事件
poller.register(socketWrapper);
poller.register(socketWrapper);
- 设置为读模式
socketWrapper.interestOps(SelectionKey.OP_READ);
- 创建事件,
PollerEvent event = null;
,并添加到同步事件队列,addEvent(event);
,队列为SynchronizedQueue<PollerEvent> events
Poller
- 一直轮训是否时间队列中有事件,交给
word
线程处理 while (true)
循环,接收事件hasEvents = events();
当事件队列有事件时,就为true,
(pe = events.poll()) != null
SelectionKey
选择器轮询时间,并进行处理
while (iterator != null && iterator.hasNext()) {
SelectionKey sk = iterator.next();
iterator.remove();
NioSocketWrapper socketWrapper = (NioSocketWrapper) sk.attachment();
// Attachment may be null if another thread has called
// cancelledKey()
// 处理事件
if (socketWrapper != null) {
processKey(sk, socketWrapper);
}
}
- 根据不同的事件,进行不同处理,
processSocket(socketWrapper, SocketEvent.OPEN_READ, true)
- 包装
socketWrapper
和event
,SocketProcessorBase<S> sc = createSocketProcessor(socketWrapper, event);
- 获取
work
线程池,Executor executor = getExecutor();
,并让线程池执行executor.execute(sc);
SocketProcessorBase
- 实现了
Runnable
,会被线程池执行 - 通过
ConnectionHandler
处理,state = getHandler().process(socketWrapper, event);
- 获取处理器,没有则创建
processor = getProtocol().createProcessor();
,并注册 - 进行处理
state = processor.process(wrapper, status);
- 根据当前时间,进行不同的处理
- 开始处理
state = service(socketWrapper);
- 解析请求首行
- 解析协议
prepareRequestProtocol();
CoyoteAdapter
处理请求头和请求体getAdapter().service(request, response);
CoyoteAdapter.service真正的执行流程
- 创建
HttpServlet
请求和响应,并将coyote
的设置进去
Request request = (Request) req.getNote(ADAPTER_NOTES);
Response response = (Response) res.getNote(ADAPTER_NOTES);
- 后置处理,特定配置
postParseSuccess = postParseRequest(req, request, res, response);
- 开始责任链执行过程
connector.getService().getContainer().getPipeline().getFirst().invoke( request, response);
- 获得
service
- 获取
engine
- 获取
pipeline
- 获取第一个阀门
- 接下来是责任链执行流程,
valve
阀门,类似执行器
Engine.invoke
- 获取主机信息
Host host = request.getHost();
- 通过
Host
的阀门进行执行host.getPipeline().getFirst().invoke(request, response);
AccessLogValve
ErrorReportValve
StandardHostValve
Host.invoke
host.getPipeline().getFirst().invoke(request, response);
AccessLogValve
ErrorReportValve
StandardHostValve
- 执行到
StandardHostValve.invoke
- 其中调用
context
应用,context.getPipeline().getFirst().invoke(request, response);
NonLoginAuthenticator
,处理认证信息StandardContextValve
Context.invoke
context.getPipeline().getFirst().invoke(request, response);
NonLoginAuthenticator
,处理认证信息StandardContextValve
- 其中
StandardContextValve.invoke
判断保护资源 wrapper.getPipeline().getFirst().invoke(request, response);
wrapper
封装了servlet
信息
Wrapper.invoke
- 创建
servlet
对象,servlet = wrapper.allocate();
,其中加载instance = loadServlet();
,定义了servlet
生命周期
- 创建
servlet = (Servlet) instanceManager.newInstance(servletClass);
- 初始化
initServlet(servlet);
,调用servlet.init(facade);
servletClass
在Context.start()
时被注册
- 为当前请求创建
Filter
链,ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
- 执行
Filter
链,filterChain.doFilter(request.getRequest(), response.getResponse());
,执行doFilter
Filter
链执行完成后,最终执行servlet.service(request, response);
- 对应到
SpringMVC
中- 执行
HttpServlet
的service
- 执行
FrameworkServlet
的do*
方法- 执行
DispatcherServlet
的doService
,调用doDispatch(request, response)