源码解读全文
Tomcat
- 下载源码
- 配置pom文件
- 启动
org.apache.catalina.startup.BootStrap下的main方法 JNDI Java Naming and Directory Interface,在一个中心注册一个东西,只需要配置这个东西的属性参数,即可使用,类似properties文件的配置
架构
conf下的server.xml配置文件
server服务器
ListenerGlobalNamingResources指定一些资源的配置信息,@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);
AccessLogValveErrorReportValveStandardHostValve
Host.invoke
host.getPipeline().getFirst().invoke(request, response);
AccessLogValveErrorReportValveStandardHostValve
- 执行到
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)