tomcat 启动
启动流程
- Bootstrap.main()
- Bootstrap bootstrap = new Bootstrap(); 实例化Bootstrap实例
- bootstrap.init(); 1.设置catalinaHome和catalinaBase 2.初始化类加载器,实例化**ClassLoaders
- setCatalinaHome(); 设置Catalina path,System.getProperty("catalina.home"),值为tomcat根目录
- setCatalinaBase(); 值为D:\workspace-e3\.metadata\.plugins\org.eclipse.wst.server.core\tmp2
- initClassLoaders(); 实例化**ClassLoaders,创建URLClassLoader
- 初始化classloader,第二个参数为父classLoader commonLoader = createClassLoader("common", null); catalinaLoader = createClassLoader("server", commonLoader); sharedLoader = createClassLoader("shared", commonLoader); 最终执行结果是,创建了commonLoader,catalinaLoader 和 sharedLoader,其中 catalinaLoader 和 sharedLoader 默认均使用 父classLoader: 即 commonLoader
- bootstrap.createClassLoader()
- 读取配置文件中配置的仓库路径(需要加载的jar包的路径) CatalinaProperties.getProperty(name + ".loader");
- CatalinaProperties类中静态块中 static {loadProperties();} 后续从properties中取
- loadProperties()方法, 读取catalina.base\\conf\\catalina.properties配置文件到prop属性中 D:\workspace-e3\.metadata\.plugins\org.eclipse.wst.server.core\tmp2\conf\catalina.properties
- bootstrap.replace()将${catalina.home}等替换成具体的路径
- 根据逗号截取出每个资源路径
- URL url = new URL(repository); 先判断是不是网络资源,即先尝试使用URL加载,若它是网络资源则能加载成功, 否则捕获异常接着下面使用本地加载
- 本地加载.根据路径结尾以*.jar,.jar或路径,创建不同类型的repository对象
- RepositoryType枚举类分类
- DIR,// 表示整个目录下的资源,包括所有Class,Jar包以及其他类型资源
- GLOB,// 表示整个目录下所有的Jar包资源,仅仅是.jar后缀的资源
- JAR,// 表示单个Jar包资源
- URL// 表示从URL上获取的Jar包资源
- 根据以上的repository列表创建classLoader. ClassLoaderFactory.createClassLoader(repositories, parent)
- 遍历repositories,判断repositoryType.目的是将每种资源转换为new URL(),并添加到URL[]数组中
0.若是RepositoryType.URL类型的资源,直接new一个URL实例即可
1.若是DIR类型,则根据路径创建java.net.URL对象;
2.若是GLOB(这里是E:\Java\apache-tomcat-7.0.82-01\lib),则遍历该目录下的jar包,创建文件,每个jar文件对应一个URL对象;
- 最后根据以上所有的url,创建URLClassLoader并返回.该类构造器接收一个URL[]数组类型 return new URLClassLoader(array)
- Thread.currentThread().setContextClassLoader(catalinaLoader); 为当前线程设置classLoader为catalinaLoader
- 若启用了安全管理,则会在这里加载一些所需的包(默认不启用) SecurityClassLoad.securityClassLoad(catalinaLoader);
- 使用catalinaLoader加载catalina类 Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina"); Object startupInstance = startupClass.newInstance();
- 设置catalina对象的parentClassLoader属性为sharedLoader, 由于前面sharedLoader默认使用的是父加载器commonLoader, 所以此处相当于设置为commonLoader org.apache.catalina.startup.Catalina.setParentClassLoader(sharedLoader);
- bootstrap对象 保存catalina的引用 catalinaDaemon = startupInstance;
- 处理"start"命令
- 1.setAwait(true) 设置catalina.await=true
- 2.daemon.load(args); 加载配置资源,通过反射调用catalina.load()方法 (1)创建digester实例,digester解析conf/server.xml文件 (2)调用Server.init()级联初始化各个组件
- Catalina中 initDirs() 设置catalina.base和catalina.home和user.dir的property属性, 检查java.io.tmpdir属性是否存在
- initNaming() 设置java.naming.factory.url.pkgs和java.naming.factory.initia这两个System.setProperty
- 创建并执行digester,使用digester解析server.xml Digester digester = createStartDigester(); Digester类按照预定的规则解析server.xml,将元素转化为对象, 包括构造对象,set属性到对象字段,同时维护相互关联关系
- new Digester() 创建digester对象
- digester.addObjectCreate() 1)添加对象创建规则ObjectCreateRule 2)SetPropertiesRule 3)SetNextRule 添加StandardServer等各级容器的关系和处理规则
- 创建Server实例,默认实现类是StandardServer, 可以通过server节点的className属性指定自己的实现,一般不需要
- 设置Server属性
- 调用setServer()将Server设置到Catalina对象中.可在本Catalina类中搜索setServer()方法
- 创建JNDI实例对象,GlobalNamingResources,并设置其属性.并调用standServer.setGlobalNamingResources()方法装配到server中
- 为Server添加生命周期监听
- 创建service实例,创建完成后,通过addService()添加到server中
- 为server添加生命周期监听器.默认未指定监听器,347行的null
- 为service添加Executor
- 为service添加Connector
- 设置属性时,将executor属性排除在外.因为Connector创建时,即ConnectorCreateRule类中, 会判断当前是否指定了executor属性.若是,则从Service中查找该名称的executor并设置到Connector中.
- 为Connector添加 生命周期监听器.默认未指定
- 添加子元素解析规则.这部分指定了Servlet容器相关的各级嵌套子节点的解析规则. 且每类嵌套子节点的解析封装为一个RuleSet类(跟进去看).包括GlobalNamingResources,Engine,Context,Cluster的解析
- 使用sax读取server.xml file = configFile();
- digester.parse(inputSource); 使用digester解析读取的xml,在此过程中会初始化各个组件实例及其依赖关系. 最后会把server.xml文件中的内容解析到StandardServer中 (创建standServer对象并维护对象间关系)
- configure();
- getXMLReader().parse(input);
- ......
- 经过java里SAXPaser解析InputSource后,调用Digester.startElement()
- 遍历rules rule.begin(namespaceURI, name, list); 分别创建StandardServer实例
- new StandardServer()构造器
- new NamingResources()
- new NamingContextListener() addLifecycleListener(namingContextListener);
- setPropertiesRule()
- standardService.addConnector()
- standardServer.addService() 向server中添加一个新的service. digester在xml解析时会注入这个关系
- digester解析会做很多初始化操作,以后细化...
- Connector con = new Connector(attributes.getValue("protocol")); 创建Connector,会有多个Connector,和xml中配置的数量有关
- Connector构造器
- setProtocol(protocol);
- 根据xml配置的协议类型,此处是Http11Protocol setProtocolHandlerClassName ("org.apache.coyote.http11.Http11Protocol");
- 实例化Http11Protocol
- Http11Protocol构造器
- endpoint = new JIoEndpoint();
- getServer().init(); 调用Server的init()方法,初始化各个组件. 它会调用各个service子容器的init()方法, 从而级联完成组件初始化 在调用init()时第3步,调用子类StandardService.initInternal(); 各个组件有个共同的父类: LifecycleBase,用于管理组件的生命周期和状态变化。 在走Server.init()前,先走父类LifecycleBase.init(),事件驱动当前组件状态的变化. 从StandardServer到StandardWrapper,都会调用initInternal(), 并伴随调用共有父类LifecycleBase.init()
- init()方法在父类LifecycleBase中, 调用父类LifecycleBase.init()
- super.initInternal(); 即父类LifecycleBase.initInternal()
- 1.先判断状态是否为LifecycleState.NEW(默认是)
2.LifecycleBase.setStateInternal(LifecycleState.INITIALIZING, null, false); 变更生命周期状态为LifecycleState.INITIALIZING 调用各个事件监听中的 初始化方法
- 3.initInternal();这个方法一般被子类覆盖,执行子类自己的逻辑 此处为StandServer.initInternal()
- StandServer.initInternal()中 super.initInternal(); 调用父类LifecycleMBeanBase.initInternal()
- LifecycleMBeanBase.initInternal()中 将容器托管到JMX,便于运维管理
- 遍历services调用service.init() services[i].init();
- StandardService.init()中 init()方法在父类LifecycleBase中, 调用父类LifecycleBase.init()
- LifecycleBase.init()中 setStateInternal(LifecycleState.INITIALIZING, null, false); 变更生命周期状态为LifecycleState.INITIALIZING(通过事件变更)
- initInternal();// 进入子类的initInternal()方法, 即调用StandardService.initInternal()
- StandardService.initInternal()中 container.init(); 此处container即为StandardEngine.init() StandardEngine的子容器standardContext及其子容器没有init初始化逻辑
- StandardEngine.init()中,略去LifecycleBase中生命周期变更的重复逻辑 StandardEngine.initInternal()中 getRealm(); 创建realm
- super.initInternal(); 即为ContainerBase.initInternal() Engine,Host,Context,Wrapper容器都拥有共同父类ContainerBase
- ContainerBase.initInternal()中 startStopExecutor = new ThreadPoolExecutor() 初始化startStopExecutor,用于管理启动和关闭的线程
- super.init()即LifecycleMBeanBase.initInternal()
- ......略去各个StandardHost.init()
- ...
- lifecycleBase.init()
- LifecycleBase.setStateInternal(LifecycleState.INITIALIZED, null, false);初始化完成 StandardContext父类LifecycleBase变更生命周期状态,调用各个事件监听中的 initializing
- initInternal();// 进入子类StandardContext.initInternal()方法
- super.initInternal(); StandardContext.initInternal()调用父类ContainerBase.initInternal() 它会创建startStopExecutor 并调用父类LifecycleMBeanBase.initInternal(); 这里会将容器托管到JMX
- this.addLifecycleListener(new TldConfig()); 添加TldConfig监听
- setStateInternal(LifecycleState.INITIALIZED, null, false); // 更新组件生命周期状态为LifecycleState.INITIALIZED
- ...
- contextConfig.lifecycleEvent() contextConfig AFTER_INIT_EVENT生命周期事件处理
- contextConfig.init(); context初始化阶段,context属性配置 tomcat提供的默认配置添加到context实例 完成对应的 每个web应用项目的配置解析(web.xml)
- createContextDigester()
- contextDigester.getParser();
- contextConfig(contextDigester); 解析config.xml配置 E:\Java\apache-tomcat-7.0.82-01\conf\context.xml
- createWebXmlDigester()
- beforeStart() Lifecycle.BEFORE_START_EVENT状态
- executor.init(); 初始化executors,即tomcat间可共享的线程池
- connector初始化
- connector.initInternal();
- adapter = new CoyoteAdapter(this); 构建与指定连接器关联的新CoyoteAdapter
- protocolHandler.setAdapter(adapter); 给 协议处理器 添加 adapter
- protocolHandler.init(); 初始化具体协议类型,如Http11Protocol协议
- AbstractHttp11JsseProtocol.init()
- endpoint初始化之前,需要初始化ssl实现类 sslImplementation = SSLImplementation.getInstance(sslImplementationName); return new org.apache.tomcat.util.net.jsse.JSSEImplementation();
- super.init(),即AbstractProtocol.init() 1.注册组件JIoEndPoint; 2.endpoint.init() 设置work threads的数量,默认为200,并创建serverSocket对象
- abstractProtocol.bind() 设置线程数,网络连接数
- 初始化acceptor线程数量,默认1个; 初始化最大连接数,此值为server.xml的connector元素的属性MaxThreads值,(若不设置则)默认200
- abstractEndpoint.getMaxThreadsWithExecutor() 返回成员变量maxThreads=200
- abstractEndpoint.setMaxConnections(getMaxThreadsWithExecutor()); 设置最大连接数
- initializeConnectionLatch(); 创建LimitLatch对象并初始化连接数 即 connectionLimitLatch = new LimitLatch(getMaxConnections());
- serverSocketFactory = new DefaultServerSocketFactory(this); 创建ServerSocketFactory
- serverSocket = serverSocketFactory.createSocket(getPort(),getBacklog()); 创建serverSocket
- 初始化mapper listener mapperListener.init();
- 容器初始化完毕,LifecycleBase会将容器的状态更改为初始化完毕 setStateInternal(LifecycleState.INITIALIZED, null, false);
- 3.daemon.start().即catalina.start() 运行各个组件,容器开始启动.
- getServer().start() 启动Server 即standardServer.start(),由于未重写该方法. 所以会先调用父类LifecycleBase.start()
- LifecycleBase.start()中 setStateInternal(LifecycleState.STARTING_PREP, null, false); // 启动前将状态设置为LifecycleState.STARTING_PREP
- startInternal(); // 模板方法调用子类逻辑
- StandardServer.startInternal();中 1.发布configure_start事件 fireLifecycleEvent(CONFIGURE_START_EVENT, null);
- 2.设置状态为starting setState(LifecycleState.STARTING); 3.globalNamingResources.start(); globalNamingResources.start();
- 4.services[i].start(); 启动多个Service子容器. 略去LifecycleBase.start()的重复逻辑, 调用standardService.startInternal()
- standardService.startInternal()中 container.start(): 启动container,此时container为StandardEngine
- StandardEngine.startInternal()中 调用super.startInternal(), 即ContainerBase.startInternal()
- ContainerBase.startInternal()中 若配置了loader,manager,cluster,realm等,则会启动这些下属组件. 在engine,host,context等容器的启动逻辑都会调用该父类(ContainerBase)的此方法用于加载启动子容器. containerBase.startInternal()会向线程池 提交启动子容器的任务,并阻塞等待子容器启动的返回结果判定是否启动成功
- ContainerBase.startInternal()中 getLoaderInternal()
- Lock readLock = loaderLock.readLock(); readLock.lock(); try { return loader; } finally { readLock.unlock(); }
- 若配置了realm组件,则启动 Realm realm = getRealmInternal(); if ((realm != null) && (realm instanceof Lifecycle)) ((Lifecycle) realm).start();
- 若有子容器,则启动 Container children[] = findChildren();
- results.add(startStopExecutor.submit(new StartChild(children[i]))); 提交启动子容器的任务,后续StandHost的操作会在新线程中完成
- StartChild.call() class StartChild implements Callable<Void> StartChild类实现Callable,会执行覆写的call()方法
- child.start(); 启动子容器,比如此处Engine的子容器就是Host 即调用standHost.start()
- StandardHost.start() 使用父类LifecycleBase中的start()方法
- LifecycleBase.start()中
- LifecycleBase.start()中 setStateInternal(LifecycleState.STARTING_PREP, null, false); 触发before_start事件,即Host容器发布before_start事件, 相关监听器会接收到通知,执行相应逻辑,如HostConfig监听器
- HostConfig.lifecycleEvent() HostConfig实现LifecycleListener接口,在StandardHost启动时生命周期发生变化时, 会调用HostConfig的lifecycleEvent()对特定事件进行逻辑处理
- 调用HostConfig.beforeStart() BEFORE_START_EVENT
- beforeStart() 会创建appBase和configBase路径所需的目录
- 判断host.getCreateDirs(),对appBase和configBase进行mkdirs()
- lifecycleBase.startInternal(); 会调用子类StandardHost.startInternal()
- StandardHost.startInternal()中 Valve[] valves = getPipeline().getValves();
- 获取错误阀的阀名,即org.apache.catalina.valves.ErrorReportValve getErrorReportValveClass()
- 若有错误阀名,尝试遍历所有阀找出这个class类 StandardPipline.getValues() 通过value.getNext()循环遍历将所有Value成数组返回
- 若没有找到,则反射创建实例,并添加到pipeline中
- super.startInternal(); 调用ContainerBase.startInternal()新起线程启动子容器(即Host的Context子容器)
- ContainerBase.startInternal()中 results.add(startStopExecutor.submit(new StartChild(children[i]))); 启动StandardContext!!!!!!后续子节点都是Context容器的操作
- 调用StandardContext.start(), 由于该类未重写start(), 所以实际上调用父类lifecycleBase.start()
- lifecycleBase.start()中 若是LifecycleState.NEW状态
- LifecycleBase.setStateInternal(LifecycleState.STARTING_PREP, null, false); 设置LifecycleState.STARTING_PREP状态,即before_start
- 调用ContextConfig.beforeStart(); // 在context启动前触发,用于更新Context的docBase属性 和 解决web目录锁的问题
- LifecycleBase.startInternal();
- 调用子类StandardContext.startInternal() 完成对web应用的初始化工作
- StandardContext.startInternal()里经过一系列操作,将状态变更为CONFIGURE_START_EVENT standardContext.fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null); 发布CONFIGURE_START_EVENT事件,contextConfig监听以完成servlet创建
- contextConfig.configureStart(); web应用初始化.解析web.xml文件, 创建wrapper,Filter,ServletContextListener等.
- contextConfig.webConfig()
- webXml.configureContext(context); 解析web.xml,将webXml对象设置给context
- Lin1388 webXml.configureContext(context); 解析servlet,将Servlet包装成Wrapper
- context.createWrapper()
- wrapper.setServletClass(servlet.getServletClass()); 将wrapper与servlet绑定
- context.addChild(wrapper); 将wrapper添加到context中
- containerBase.addChildInternal(child);
- child.start(); 即standardWraper.start()
- Wrapper容器 StandardWrapper.start()
- LifecyclesetStateInternal(LifecycleState.STARTED, null, false); 设置LifecycleState.STARTED状态,即after_start
- 调用context.setDocBase(originalDocBase);
- containerBase.threadStart(); 启动Context层级的后台任务进程.Cluster后台任务(包括部署变更检测,心跳).Pipeline中Value的后台任务处理(如果有定时处理任务)
- ContainerBase.startInternal()中 setState(LifecycleState.STARTING); 设置容器状态为STARTING,此时会触发START_EVENT生命周期事件.即start事件
- 调用HostConfig.start(); Host启动时触发,完成服务器启动过程中的 Web应用部署. 需要 Host的deployOnstartup="true"才会在服务器启动时部署web应用.
- 若有管道,则启动 if (pipeline instanceof Lifecycle) ((Lifecycle) pipeline).start();
- executor.start(); 启动service容器的多个线程池executors
- connector.start(); 启动service组件的多个connector
- connector.startInternal()
- protocolHandler.start(); 启动 协议处理器
- endpoint.start();
- createExecutor(); 创建endpoint私有的线程池,即ThreadPoolExecutor线程池
- abstractEndpoint.createExecutor()
- new TaskQueue(); 用来运行线程池执行器的任务队列,该类extends LinkedBlockingQueue<Runnable> new TaskThreadFactory() implements ThreadFactory 线程工厂,用于创建并返回线程 executor = new ThreadPoolExecutor() 根据前两者 创建线程池
- initializeConnectionLatch(); 创建LimitLatch对象,之前init时已经创建.此处直接返回
- startAcceptorThreads(); 创建多个Acceptors
- getAcceptorThreadCount(); 获取acceptor线程数量,默认1
- return new JIoEndpoint.Acceptor() implements Runnable; 创建JIoEndpoint
- Thread t = new Thread(acceptors[i], threadName); 根据JIoEndpoint创建线程,且是守护线程
- mapperListener.start(); 启动 mapperListener
- findDefaultHost(); 从engine中获取defaultHost并设置给mapper
- 从engine中获取defaultHost并设置给mapper mapper.setDefaultHostName(defaultHost);
- addListeners(engine);
- container.addContainerListener(this); container.addLifecycleListener(this); addListeners(child); 其中this为engine,child为host.即给engine注册监听
- registHost() 向mapper注册host及其下的context,wrapper
- mapper.addHost(host.getName(), aliases, host);
- registerContext((Context) container); 向mapper注册context
- prepareWrapperMappingInfo(context, (Wrapper) container, wrappers);
bootstrap.init()
创建 commonClassLoader,和 两个子 类加载器 catalinaLoader 和 sharedLoader,当然都是 URLClassLoader 实例,加载 一些 Jar.
设置当前线程的上下文类加载器为 catalinaLoader
设置 Catalina 的 父类加载器为 sharedLoader
处理 start 命令
分为 load 和 start 两步
load
读取 conf/server.xml 配置,使用 digester 解析,组装对象.
server.init() 主要遍历 services,调用其 init() 方法
状态变更: LifecycleState.NEW -> LifecycleState.INITIALIZING -> initInternal() -> LifecycleState.INITIALIZED
service.init()
调用 engine.init(),初始化executor,遍历初始化 connectors
Connector.init()
创建 CoyoteAdapter
protocolHandler 关联 adapter
protocolHandler.init(),这里面会初始化 endpoint
mapperListener.init()
StandEngine.init()
engine,host,context,wrapper 都继承自 ContainerBase,ContainerBase里会起 startStopExecutor 线程池,这个线程池用于子容器启动,父容器会等待子容器启动完成.
start
Catalina.start()
调用 server.start()
StandardServer.start()
触发 CONFIGURE_START_EVENT 事件,设置自身的状态为 STARTING,遍历调用 services.start()
StandService.start()
设置状态为 STARTING,调用 engine.start(),excutors.start(),connector.start()
StandEngine.start()
会走父类 ContainerBase.startInternal(),在 ContainerBase 中,若配了 loader,manager, cluster, realm 则 启动.
然后就查找所有子容器,每个子容器都交由 startStopExecutor 线程池 执行 StartChild 的逻辑,调用 child.start().并通过 future.get() 阻塞等待所有子容器启动成功.
pipeline.start()
设置线程状态为 STARTING,触发 START_EVENT 生命周期事件.
启动一个 ContainerBackgroundProcessor 后台线程.
ContainerBase.startInternal()代码
@Override
protected synchronized void startInternal() throws LifecycleException {
// Start our subordinate components, if any.启动下属组件
Loader loader = getLoaderInternal();
if ((loader != null) && (loader instanceof Lifecycle))// 若配置了loader则启动
((Lifecycle) loader).start();
logger = null;
getLogger();
Manager manager = getManagerInternal();
if ((manager != null) && (manager instanceof Lifecycle))
((Lifecycle) manager).start();
Cluster cluster = getClusterInternal();
if ((cluster != null) && (cluster instanceof Lifecycle))// 若配置了集群,则启动
((Lifecycle) cluster).start();
Realm realm = getRealmInternal();
if ((realm != null) && (realm instanceof Lifecycle))// 若配置了安全组件Realm,则启动
((Lifecycle) realm).start();
DirContext resources = getResourcesInternal();
if ((resources != null) && (resources instanceof Lifecycle))
((Lifecycle) resources).start();
// Start our child containers, if any.启动子容器,如果有的话.
Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<Future<Void>>();
for (int i = 0; i < children.length; i++) { // 提交 启动子容器的任务.并阻塞当前线程等待执行结果
results.add(startStopExecutor.submit(new StartChild(children[i]))); // 子容器使用 startStopExecutor 调用新线程来启动
}
boolean fail = false;
for (Future<Void> result : results) { // 启动 多个子容器的执行结果
try {
result.get(); // 阻塞直到所有子容器启动完毕
} catch (Exception e) {
log.error(sm.getString("containerBase.threadedStartFailed"), e);
fail = true;
}
}
if (fail) {
throw new LifecycleException(
sm.getString("containerBase.threadedStartFailed"));
}
// Start the Valves in our pipeline (including the basic), if any.启动容器持有的Pipeline组件的Value.若有管道,则启动
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();
// 设置容器状态为STARTING,此时会触发START_EVENT生命周期事件.
setState(LifecycleState.STARTING);
// Start our thread. 启动该层级的后台定时任务进程(不同容器调用,则启动不同容器的后台线程).用于处理如 Cluster 后台任务(包括部署变更检测,心跳).Realm 后台任务处理.Pipeline 中 Value 的后台任务处理(如果有定时处理任务)
threadStart();
}
StandardHost.startInternal()
不存在errorValve则创建,调用 ContainerBase.startInternal() 启动子容器.子容器是在 HostConfig.deployXxx里通过host.addChild(context)
添加进来的.
StandContext.startInternal()
创建 WebappLoader 并启动
触发 CONFIGURE_START_EVENT 事件,contextConfig 监听以完成 servlet 创建
遍历启动子容器
启动pipline
触发listener的各种事件
初始化filter
初始化servlets,调用 load-on-startup 的 servlet 的 init() 方法
遍历 wraper,调用 wrapper.load() 加载 wrapper
StandWrapper.startInternal()
没什么重要逻辑