赞
踩
而start方法反射调用了Catalina的start方法。
daemon.start();
public void start() throws Exception {
if (catalinaDaemon == null) {
init();
}
Method method = catalinaDaemon.getClass().getMethod("start", (Class [])null);
method.invoke(catalinaDaemon, (Object [])null);
}
public void start() { if (getServer() == null) { load(); } //... long t1 = System.nanoTime(); // Start the new server try { //执行start getServer().start(); } catch (LifecycleException e) { //... } // Register shutdown hook if (useShutdownHook) { if (shutdownHook == null) { shutdownHook = new CatalinaShutdownHook(); } Runtime.getRuntime().addShutdownHook(shutdownHook); } if (await) { await(); stop(); } }
这里的start同样会调用LifeCycleBase的start方法,start较init来说多了一种状态STARTING
,对于正常流程来说,先由LifecycleBase
改变当前状态值为STARTING_PREP
,并发出事件通知,即执行当前事件的监听器,然后执行各个节点的start方法,在启动过程中,将状态值设置为STARTING
,并执行事件监听器,启动结束后,将状态设置为初始化完成STARTED
,并发出事件通知。
LifecycleBase#start
public final synchronized void start() throws LifecycleException { //... try { setStateInternal(LifecycleState.STARTING_PREP, null, false); startInternal(); if (state.equals(LifecycleState.FAILED)) { // This is a 'controlled' failure. The component put itself into the // FAILED state so call stop() to complete the clean-up. stop(); } else if (!state.equals(LifecycleState.STARTING)) { // Shouldn't be necessary but acts as a check that sub-classes are // doing what they are supposed to. invalidTransition(Lifecycle.AFTER_START_EVENT); } else { setStateInternal(LifecycleState.STARTED, null, false); } } catch (Throwable t) { handleSubClassException(t, "lifecycleBase.startFail", toString()); } }
StadardServer#startInternal
protected void startInternal() throws LifecycleException { fireLifecycleEvent(CONFIGURE_START_EVENT, null); setState(LifecycleState.STARTING); globalNamingResources.start(); // Start our defined Services //启动services组件 synchronized (servicesLock) { for (int i = 0; i < services.length; i++) { services[i].start(); } } //执行生命周期事件 if (periodicEventDelay > 0) { monitorFuture = getUtilityExecutor().scheduleWithFixedDelay( new Runnable() { @Override public void run() { startPeriodicLifecycleEvent(); } }, 0, 60, TimeUnit.SECONDS); } }
这里的Listener主要执行了NamingContextListener
,做了一些JNDI资源的初始化。然后就是执行service容器的start方法。
StadardService#startInternal
protected void startInternal() throws LifecycleException { if(log.isInfoEnabled()) log.info(sm.getString("standardService.start.name", this.name)); setState(LifecycleState.STARTING); //engine启动 if (engine != null) { synchronized (engine) { engine.start(); } } // 启动Executor线程池 synchronized (executors) { for (Executor executor: executors) { executor.start(); } } // 启动MapperListener mapperListener.start(); // 启动Connector synchronized (connectorsLock) { for (Connector connector: connectors) { // If it has already failed, don't try and start it if (connector.getState() != LifecycleState.FAILED) { connector.start(); } } } }
engine的启动和初始化一样,会调用父类ContainerBase
的startInternal
方法,主要分为3个步骤
ContainerBase#startInternal
protected synchronized void startInternal() throws LifecycleException { // ... // 把子容器的启动放在线程池中处理 Container[] children = findChildren(); List<Future<Void>> results = new ArrayList<>(); for (int i = 0; i < children.length; i++) { results.add(startStopExecutor.submit(new StartChild(children[i]))); } MultiThrowable multiThrowable = null; // 阻塞当前线程,直到子容器start完成 for (Future<Void> result : results) { try { result.get(); } catch (Throwable e) { log.error(sm.getString("containerBase.threadedStartFailed"), e); if (multiThrowable == null) { multiThrowable = new MultiThrowable(); } multiThrowable.add(e); } } //... // 启用Pipeline if (pipeline instanceof Lifecycle) { ((Lifecycle) pipeline).start(); } setState(LifecycleState.STARTING); // 开启ContainerBackgroundProcessor线程用于调用子容器的backgroundProcess方法,默认情况下backgroundProcessorDelay=-1。 if (backgroundProcessorDelay > 0) { monitorFuture = Container.getService(ContainerBase.this).getServer() .getUtilityExecutor().scheduleWithFixedDelay( new ContainerBackgroundProcessorMonitor(), 0, 60, TimeUnit.SECONDS); } }
启动子容器
startStopExecutor
是在init阶段被创建的,默认情况下会创建线程池InlineExecutorService
,这个线程池的coreSize=maxSize=1。而这个可以在server.xml
里通过startStopThreads来配置,这里需要注意的是,startStopExecutor
的创建是在ContainerBase
的初始化方法调用时,意味着每个继承了ContainerBase
的容器在启动子容器时都维护了一个自己的线程池,并可以分别修改线程池属性。继承了ContainerBase
的如下:
ContainerBase会把StartChild任务丢给线程池处理,得到Future,并且会遍历所有的Future进行阻塞result.get(),这个操作是将异步启动转同步,子容器启动完成才会继续运行。然后再来看看submit到线程池的StartChild任务,它实现了Callable
接口,在call里面完成子容器的start动作,而start方法依然是调用LifecycleBase
的start方法。
private static class StartChild implements Callable<Void> {
private Container child;
public StartChild(Container child) {
this.child = child;
}
@Override
public Void call() throws LifecycleException {
child.start();
return null;
}
}
由于Host在init阶段没有进行初始化,所以在调用start方法时,状态为NEW,需要先进行初始化。
由于默认实现StandardHost
内部没有实现initInternal
,所以这里的初始化执行了ContainerBase
的initInternal
方法,详见ContainerBase的initInternal
StandardHost#startInternal
private String errorReportValveClass ="org.apache.catalina.valves.ErrorReportValve"; protected synchronized void startInternal() throws LifecycleException { // Set error report valve // errorValve默认使用org.apache.catalina.valves.ErrorReportValve String errorValve = getErrorReportValveClass(); if ((errorValve != null) && (!errorValve.equals(""))) { try { boolean found = false; Valve[] valves = getPipeline().getValves(); for (Valve valve : valves) { if (errorValve.equals(valve.getClass().getName())) { found = true; break; } } if(!found) { // 将Valve添加到 Pipeline 中,注意是添加到 basic valve 的前面 Valve valve = (Valve) Class.forName(errorValve).getConstructor().newInstance(); getPipeline().addValve(valve); } } catch (Throwable t) { //... } } // 调用父类 ContainerBase super.startInternal(); }
在Pipeline里寻找是否存在ErrorReportValve
,如果不存在则实例化后添加到Pipeline。那么Pipline和Valve是什么呢
Pipeline是管道组件,用于封装了一组有序的Valve,便于Valve顺序地传递或者处理请求
Valve可以理解为请求拦截器。
Pipeline也是一个Lifecycle组件, 默认实现是StandardPipeline
,这段被定义在ContainerBase
中,也就意味着同上面的startStopExecutor
一样,每个容器都维护了一个自己的拦截器链。
protected final Pipeline pipeline = new StandardPipeline(this);
而Valve的接口如下:
public interface Valve {
public Valve getNext();
public void setNext(Valve valve);
public void backgroundProcess();
public void invoke(Request request, Response response) throws IOException, ServletException;
public boolean isAsyncSupported();
}
而对于Host来说,Valve在server.xml`配置了一个日志拦截器。
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true" startStopThreads="4" >
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
另一个默认的Valve来自于StandardHost
的构造方法。这里每个实现了ContainerBase
的容器都会在构造方法里创建一个默认的Valve。
public StandardHost() {
super();
pipeline.setBasic(new StandardHostValve());
}
所以StandardHost Pipeline 包含的 Valve 组件:
而在添加ErrorReportValve
时,会将ErrorReportValve
添加到basic之前,first之后。
StandardPiepline#addValve
public void addValve(Valve valve) { // Validate that we can add this Valve if (valve instanceof Contained) ((Contained) valve).setContainer(this.container); //... // Add this Valve to the set associated with this Pipeline if (first == null) { first = valve; valve.setNext(basic); } else { Valve current = first; while (current != null) { if (current.getNext() == basic) { //设置到basic之前 current.setNext(valve); valve.setNext(basic); break; } current = current.getNext(); } } container.fireContainerEvent(Container.ADD_VALVE_EVENT, valve); }
在ContainerBase#startInternal
方法中,执行完子容器的启动后会启动pipeline。这里也会先执行pipeline的初始化在执行启动,不过初始化时除了状态的变更和事件通知之外,什么也没做,而在启动阶段,会遍历所有的Valve,如果当前Valve是 Lifecycle 的子类,则会调用其 start 方法启动 Valve 组件。
StandardPipeline#startInternal
protected synchronized void startInternal() throws LifecycleException { // Start the Valves in our pipeline (including the basic), if any Valve current = first; if (current == null) { current = basic; } //遍历 Valve 链表,如果 Valve 是 Lifecycle 的子类,则会调用其 start 方法启动 Valve 组件 while (current != null) { if (current instanceof Lifecycle) ((Lifecycle) current).start(); current = current.getNext(); } setState(LifecycleState.STARTING); }
StandardHost的启动到这里就结束了,从代码可以看出,并没有做过多的事情。而对于Host的真正操作是在监听器HostConfig
里,即每次LifeCycle状态变更时发送的事件通知。HostConfig
是在解析xml阶段配置的,主要是找到webapp目录,并解压war包。
HostConfig主要负责处理start和stop事件
HostConfig#lifecycleEvent
public void lifecycleEvent(LifecycleEvent event) { //判断事件是否由 Host 发出,并且为 HostConfig 设置属性 //.. // Process the event that has occurred if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) { check(); } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) { beforeStart(); } else if (event.getType().equals(Lifecycle.START_EVENT)) { start(); } else if (event.getType().equals(Lifecycle.STOP_EVENT)) { stop(); } } public void start() { //... if (host.getDeployOnStartup()) deployApps(); } protected void deployApps() { File appBase = host.getAppBaseFile(); File configBase = host.getConfigBaseFile(); // 过滤掉hostConfig.ignorePath String[] filteredAppPaths = filterAppPaths(appBase.list()); // 部署 xml 描述文件 deployDescriptors(configBase, configBase.list()); // 解压 war 包 deployWARs(appBase, filteredAppPaths); // 处理扩展的文件 deployDirectories(appBase, filteredAppPaths); }
解压war包
protected void deployWARs(File appBase, String[] files) { //... for (int i = 0; i < files.length; i++) { File war = new File(appBase, files[i]); if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".war") && war.isFile() && !invalidWars.contains(files[i]) ) { //... results.add(es.submit(new DeployWar(this, cn, war))); } } } private static class DeployWar implements Runnable { private HostConfig config; private ContextName cn; private File war; @Override public void run() { config.deployWAR(cn, war); } } //部署Web应用程序时,默认情况下是否应将XML文件复制到 $CATALINA_BASE / conf / <engine> / <host> protected boolean copyXML = false; protected String contextClass = "org.apache.catalina.core.StandardContext"; protected void deployWAR(ContextName cn, File war) { //... Context context = null; //实例化context if (deployThisXML && useXml && !copyXML) { //从扩展目录的xml解析并实例化 这个是有限制条件的 context = (Context) digester.parse(xml); }else if (deployThisXML && xmlInWar) { //从META-INF/context.xml目录下的jar包里解析并实例化 context = (Context) digester.parse(istream); }else if (!deployThisXML && xmlInWar) { // ... } else { //一般情况下的实例化 context = (Context) Class.forName(contextClass).getConstructor().newInstance(); } //... //实例化ContextConfig,并将其作为监听器add到StandardContext中 Class<?> clazz = Class.forName(host.getConfigClass()); LifecycleListener listener = (LifecycleListener) clazz.getConstructor().newInstance(); context.addLifecycleListener(listener); context.setName(cn.getName()); context.setPath(cn.getPath()); context.setWebappVersion(cn.getVersion()); context.setDocBase(cn.getBaseName() + ".war"); //添加并启动子容器 host.addChild(context); }
Context的启动和Host类似。init阶段就不再赘述了。
StandardContext#startInternal
protected synchronized void startInternal() throws LifecycleException { //由于这个方法比较长,这里节选重点部分 //调用ContextConfig 从web.xml 或者 Servlet3.0 的注解配置,读取 Servlet 相关的配置信息,比如 Filter、Servlet、Listener 等 fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null); // Call ServletContainerInitializers 执行ServletContainerInitializer的SPI实现类 for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :initializers.entrySet()) { entry.getKey().onStartup(entry.getValue(),getServletContext()); } // 初始化filter if (ok) { if (!filterStart()) { log.error(sm.getString("standardContext.filterFail")); ok = false; } } // StandardWrapper 实例化并且启动 Servlet,由于 Servlet 存在 loadOnStartup 属性 // 因此使用了 TreeMap,根据 loadOnStartup 值 对 Wrapper 容器进行排序,然后依次启动 Servlet // Load and initialize all "load on startup" servlets if (ok) { if (!loadOnStartup(findChildren())){ log.error(sm.getString("standardContext.servletFail")); ok = false; } } }
由于这段代码比较复杂,这里说一下大概的内容。
CONFIGURE_START_EVENT
事件,该事件主要由ContextConfig处理。针对几个重点的部分作详细研究。
对于该事件的处理主要在ContextConfig#webConfig
。
web.xml
。WebXml webXml = createWebXml();
// Parse context level web.xml
InputSource contextWebXml = getContextWebXmlSource();
if (!webXmlParser.parseWebXml(contextWebXml, webXml, false)) {
ok = false;
}
web-fragment.xml
,tomcat提供的jar包会忽略此xml文件Map<String,WebXml> fragments = processJarsForWebFragments(webXml, webXmlParser);
Set<WebXml> orderedFragments = null;
orderedFragments =WebXml.orderWebFragments(webXml, fragments, sContext);
processServletContainerInitializers(); protected void processServletContainerInitializers() { List<ServletContainerInitializer> detectedScis; try { WebappServiceLoader<ServletContainerInitializer> loader = new WebappServiceLoader<>(context); detectedScis = loader.load(ServletContainerInitializer.class); } catch (IOException e) { //... } for (ServletContainerInitializer sci : detectedScis) { initializerClassMap.put(sci, new HashSet<Class<?>>()); HandlesTypes ht; try { ht = sci.getClass().getAnnotation(HandlesTypes.class); } catch (Exception e) { //... continue; } if (ht == null) { continue; } Class<?>[] types = ht.value(); if (types == null) { continue; } for (Class<?> type : types) { if (type.isAnnotation()) { handlesTypesAnnotations = true; } else { handlesTypesNonAnnotations = true; } Set<ServletContainerInitializer> scis = typeInitializerMap.get(type); if (scis == null) { scis = new HashSet<>(); typeInitializerMap.put(type, scis); } scis.add(sci); } } }
获取ServletContainerInitializer
的实现类,并将其保存在ContextConfig的map中,ServletContainerInitializer
是servlet的spi机制,可以通过 HandlesTypes 筛选出相关的 servlet 类,并对 ServletContext 进行额外处理。自定义的ServletContainerInitializer
的实现类,需要将类名的项目路径配置在META-INF/services/javax.servlet.ServletContainerInitializer
文件中。以下是一个例子。
@HandlesTypes( Test.class )
public class CustomServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
for ( Class<?> type : c ) {
System.out.println( type.getName() );
}
}
}
javax.servlet.ServletContainerInitializer
com.test.CustomServletContainerInitializer
web.xml
,则会先扫描 WEB-INF/classes 目录下面的 class 文件,然后扫描 WEB-INF/lib 目录下面的 jar 包,解析字节码读取 servlet 相关的注解配置类,将解析完的信息设置到WebXml对象中。重点代码如下:ContextConfig#processAnnotationsStream
protected void processAnnotationsStream(InputStream is, WebXml fragment, boolean handlesTypesOnly, Map<String,JavaClassCacheEntry> javaClassCache) throws ClassFormatException, IOException { //对字节码文件进行解析。 ClassParser parser = new ClassParser(is); JavaClass clazz = parser.parse(); //处理注解@HandlesTypes checkHandlesTypes(clazz, javaClassCache); if (handlesTypesOnly) { return; } //获取其注解,并把 WebServlet、WebFilter、WebListener 注解的类添加到 WebXml 实例中 processClass(fragment, clazz); } //解析servlet3.0注解 protected void processClass(WebXml fragment, JavaClass clazz) { AnnotationEntry[] annotationsEntries = clazz.getAnnotationEntries(); if (annotationsEntries != null) { String className = clazz.getClassName(); for (AnnotationEntry ae : annotationsEntries) { String type = ae.getAnnotationType(); if ("Ljavax/servlet/annotation/WebServlet;".equals(type)) { processAnnotationWebServlet(className, ae, fragment); }else if ("Ljavax/servlet/annotation/WebFilter;".equals(type)) { processAnnotationWebFilter(className, ae, fragment); }else if ("Ljavax/servlet/annotation/WebListener;".equals(type)) { fragment.addListener(className); } else { // Unknown annotation - ignore } } } }
private void configureContext(WebXml webxml) { //省略部分代码... // 设置 Filter for (FilterDef filter : webxml.getFilters().values()) { if (filter.getAsyncSupported() == null) { filter.setAsyncSupported("false"); } context.addFilterDef(filter); } // 设置 FilterMapping,即 Filter 的 URL 映射 for (FilterMap filterMap : webxml.getFilterMappings()) { context.addFilterMap(filterMap); } // 往 Context 中添加子容器 Wrapper,即 Servlet for (ServletDef servlet : webxml.getServlets().values()) { Wrapper wrapper = context.createWrapper(); wrapper.setName(servlet.getServletName()); Map<String,String> params = servlet.getParameterMap(); for (Entry<String, String> entry : params.entrySet()) { wrapper.addInitParameter(entry.getKey(), entry.getValue()); } wrapper.setServletClass(servlet.getServletClass()); wrapper.setOverridable(servlet.isOverridable()); context.addChild(wrapper); } //还有很多属性被加载,这里就不一一赘述了 }
当context.addChild(wrapper)
时,会调用StandardContext的addChild,然后会调用ContainerBase的addChild,最后进行wrapper的启动。Wrapper的初始化和Context没什么区别。
StandardWrapper没有子容器,所以启动时主要完成了jmx事件通知。
StandardWrapper#startInternal
protected synchronized void startInternal() throws LifecycleException { // 发出 j2ee.state.starting 事件通知 if (this.getObjectName() != null) { Notification notification = new Notification("j2ee.state.starting", this.getObjectName(), sequenceNumber++); broadcaster.sendNotification(notification); } // 调用ContainerBase的startInternal,见Engine启动的ContainerBase#startInternal super.startInternal(); setAvailable(0L); //running 事件通知 if (this.getObjectName() != null) { Notification notification = new Notification("j2ee.state.running", this.getObjectName(), sequenceNumber++); broadcaster.sendNotification(notification); } }
ContextConfig#webConfig
加载所有jar包下 META-INF/resources/的静态资源文件。
processResourceJARs(resourceJars); protected void processResourceJARs(Set<WebXml> fragments) { for (WebXml fragment : fragments) { URL url = fragment.getURL(); try { if ("jar".equals(url.getProtocol()) || url.toString().endsWith(".jar")) { try (Jar jar = JarFactory.newInstance(url)) { jar.nextEntry(); String entryName = jar.getEntryName(); while (entryName != null) { if (entryName.startsWith("META-INF/resources/")) { context.getResources().createWebResourceSet( WebResourceRoot.ResourceSetType.RESOURCE_JAR, "/", url, "/META-INF/resources"); break; } jar.nextEntry(); entryName = jar.getEntryName(); } } } else if ("file".equals(url.getProtocol())) { File file = new File(url.toURI()); File resources = new File(file, "META-INF/resources/"); if (resources.isDirectory()) { context.getResources().createWebResourceSet( WebResourceRoot.ResourceSetType.RESOURCE_JAR, "/", resources.getAbsolutePath(), null, "/"); } } } catch (IOException ioe) { //... } } }
最后将所有ServletContainerInitializer
实现类设置到context中。
if (ok) {
for (Map.Entry<ServletContainerInitializer,
Set<Class<?>>> entry :
initializerClassMap.entrySet()) {
if (entry.getValue().isEmpty()) {
context.addServletContainerInitializer(
entry.getKey(), null);
} else {
context.addServletContainerInitializer(
entry.getKey(), entry.getValue());
}
}
}
在ContextConfig处理完start事件后,会先调用ServletContainerInitializer#onStartup
方法。
StandardContext#startInternal
//调用 ServletContainerInitializer#onStartup()
for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :
initializers.entrySet()) {
try {
entry.getKey().onStartup(entry.getValue(),
getServletContext());
} catch (ServletException e) {
log.error(sm.getString("standardContext.sciFail"), e);
ok = false;
break;
}
}
public boolean listenerStart() { // 实例化所有listener String[] listeners = findApplicationListeners(); Object[] results = new Object[listeners.length]; boolean ok = true; for (int i = 0; i < results.length; i++) { try { String listener = listeners[i]; results[i] = getInstanceManager().newInstance(listener); } catch (Throwable t) { //... ok = false; } } // 将listener按照类型分为2个list存储 List<Object> eventListeners = new ArrayList<>(); List<Object> lifecycleListeners = new ArrayList<>(); for (int i = 0; i < results.length; i++) { if ((results[i] instanceof ServletContextAttributeListener) || (results[i] instanceof ServletRequestAttributeListener) || (results[i] instanceof ServletRequestListener) || (results[i] instanceof HttpSessionIdListener) || (results[i] instanceof HttpSessionAttributeListener)) { eventListeners.add(results[i]); } if ((results[i] instanceof ServletContextListener) || (results[i] instanceof HttpSessionListener)) { lifecycleListeners.add(results[i]); } } //... //调用ServletContextListener的contextInitialized方法 for (int i = 0; i < instances.length; i++) { if (!(instances[i] instanceof ServletContextListener)) continue; ServletContextListener listener = (ServletContextListener) instances[i]; try { fireContainerEvent("beforeContextInitialized", listener); if (noPluggabilityListeners.contains(listener)) { listener.contextInitialized(tldEvent); } else { listener.contextInitialized(event); } fireContainerEvent("afterContextInitialized", listener); } catch (Throwable t) { //... ok = false; } } return ok; }
eventListeners
和lifecycleListeners
。lifecycleListeners
中的ServletContextListener
,执行它的contextInitialized
方法。public boolean filterStart() { // Instantiate and record a FilterConfig for each defined filter boolean ok = true; synchronized (filterConfigs) { filterConfigs.clear(); for (Entry<String,FilterDef> entry : filterDefs.entrySet()) { String name = entry.getKey(); try { ApplicationFilterConfig filterConfig = new ApplicationFilterConfig(this, entry.getValue()); filterConfigs.put(name, filterConfig); } catch (Throwable t) { ok = false; } } } return ok; } ApplicationFilterConfig(Context context, FilterDef filterDef) throws ClassCastException, ReflectiveOperationException, ServletException, NamingException, IllegalArgumentException, SecurityException { super(); this.context = context; this.filterDef = filterDef; // Allocate a new filter instance if necessary if (filterDef.getFilter() == null) { getFilter(); } else { this.filter = filterDef.getFilter(); context.getInstanceManager().newInstance(filter); initFilter(); } }
将filterDefs转换成ApplicationFilterConfig,filterDefs是ContextConfig在解析servlet注解时用来保存filter信息的对象,并在ApplicationFilterConfig的构造方法中完成调用filter.init()
。举个例子。这里会调用HelloFilter的init方法。
@WebFilter( urlPatterns = {"/*"} ) public class HelloFilter implements Filter { public HelloFilter() { } public void init(FilterConfig filterConfig) throws ServletException { System.out.println("filter is init"); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("filter is running"); chain.doFilter(request, response); } public void destroy() { System.out.println("filter is destroy"); } }
public boolean loadOnStartup(Container[] children) { TreeMap<Integer, ArrayList<Wrapper>> map = new TreeMap<>(); for (int i = 0; i < children.length; i++) { Wrapper wrapper = (Wrapper) children[i]; int loadOnStartup = wrapper.getLoadOnStartup(); if (loadOnStartup < 0) continue; Integer key = Integer.valueOf(loadOnStartup); ArrayList<Wrapper> list = map.get(key); if (list == null) { list = new ArrayList<>(); map.put(key, list); } list.add(wrapper); } // Load the collected "load on startup" servlets for (ArrayList<Wrapper> list : map.values()) { for (Wrapper wrapper : list) { try { wrapper.load(); } catch (ServletException e) { //... } } } return true; }
loadOnStartup
大小将wrapper进行排序,loadOnStartup
值相同的放在同一个list。loadOnStartup>=0
的会在启动阶段被加载,而如果loadOnStartup
为默认值-1的话,是在首次调用时加载,这里的load方法调用的是StandardWrapper#load()
。public synchronized void load() throws ServletException {
// 实例化 Servlet,并且调用 init 方法完成初始化
instance = loadServlet();
}
public synchronized Servlet loadServlet() throws ServletException {
InstanceManager instanceManager = ((StandardContext)getParent()).getInstanceManager();
servlet = (Servlet) instanceManager.newInstance(servletClass);
//调用servlet的init
initServlet(servlet);
fireContainerEvent("load", this);
}
到这里Engine的启动就结束了。
public void startInternal() throws LifecycleException { setState(LifecycleState.STARTING); Engine engine = service.getContainer(); if (engine == null) { return; } findDefaultHost(); addListeners(engine); Container[] conHosts = engine.findChildren(); for (Container conHost : conHosts) { Host host = (Host) conHost; if (!LifecycleState.NEW.equals(host.getState())) { // Registering the host will register the context and wrappers registerHost(host); } } }
localhost
MapperListener
作为ContainerListener
和LifecycleListener
递归设置到当前容器及其所有子容器MapperListener
中,以备请求时进行匹配。private void registerHost(Host host) { String[] aliases = host.findAliases(); //设置host mapper.addHost(host.getName(), aliases, host); for (Container container : host.findChildren()) { if (container.getState().isAvailable()) { registerContext((Context) container); } } // Default host may have changed findDefaultHost(); } private void registerContext(Context context) { String contextPath = context.getPath(); if ("/".equals(contextPath)) { contextPath = ""; } Host host = (Host)context.getParent(); WebResourceRoot resources = context.getResources(); String[] welcomeFiles = context.findWelcomeFiles(); List<WrapperMappingInfo> wrappers = new ArrayList<>(); for (Container container : context.findChildren()) { //将wrapper封装成WrapperMappingInfo prepareWrapperMappingInfo(context, (Wrapper) container, wrappers); } //将所有wrapper设置到Mapper中 mapper.addContextVersion(host.getName(), host, contextPath, context.getWebappVersion(), context, welcomeFiles, resources, wrappers); } private final Map<Context, ContextVersion> contextObjectToContextVersionMap = new ConcurrentHashMap<>(); public void addContextVersion(String hostName, Host host, String path, String version, Context context, String[] welcomeResources, WebResourceRoot resources, Collection<WrapperMappingInfo> wrappers) { //省略了部分代码 contextObjectToContextVersionMap.put(context, newContextVersion); }
首先将Host设置到Mapper,然后解析子容器Context,将解析出的Wrapper封装成WrapperMappingInfo
设置到MapperListener的Mapper中。这里放一张截图方便理解。其中/tomcat-test
是测试用例servlet,其他的是Tomcat自带。
StandardConnector#startInternal
protected void startInternal() throws LifecycleException { //校验端口 if (getPortWithOffset() < 0) { throw new LifecycleException(sm.getString( "coyoteConnector.invalidPort", Integer.valueOf(getPortWithOffset()))); } setState(LifecycleState.STARTING); try { // protocolHandler.start(); } catch (Exception e) { //... } }
根据Connector的init阶段,这里的protocolHandler的实现是Http11NioProtocol
,而Http11NioProtocol
的start方法会调用父类AbstractProtocol#start()
,这个方法里调用了endpoint的start。
AbstractProtocol#start()
public void start() throws Exception {
endpoint.start();
}
Connector启动的重点是在Endpoint的启动,这里会启动两个线程组,Poller
和s
。
NioEndpoint#start()
public void startInternal() throws Exception { if (!running) { running = true; paused = false; //SocketProcessor对象的缓存 if (socketProperties.getProcessorCache() != 0) { processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE, socketProperties.getProcessorCache()); } //缓存poller事件 if (socketProperties.getEventCache() != 0) { eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE, socketProperties.getEventCache()); } //字节缓冲区高速缓存 if (socketProperties.getBufferPool() != 0) { nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE, socketProperties.getBufferPool()); } // Create worker collection if (getExecutor() == null) { createExecutor(); } //初始化连接数计数器,默认是1000 //private int maxConnections = 10000; initializeConnectionLatch(); // Start poller threads pollers = new Poller[getPollerThreadCount()]; for (int i = 0; i < pollers.length; i++) { pollers[i] = new Poller(); Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-" + i); pollerThread.setPriority(threadPriority); pollerThread.setDaemon(true); pollerThread.start(); } startAcceptorThreads(); } }
除了配置一些缓存之外,这里创建了三种不同类型的Thread。Poller
线程、Acceptor
线程以及一个线程池。
AbstractEndpoint#createExecutor
private int minSpareThreads = 10;
private int maxThreads = 200;
public void createExecutor() {
internalExecutor = true;
TaskQueue taskqueue = new TaskQueue();
TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
taskqueue.setParent( (ThreadPoolExecutor) executor);
}
这里默认的coresize=10,maxsize=200,keepalive=60s,这个线程池用来处理servlet请求。
private int pollerThreadCount = 1;
pollers = new Poller[getPollerThreadCount()];
for (int i = 0; i < pollers.length; i++) {
pollers[i] = new Poller();
Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-" + i);
pollerThread.setPriority(threadPriority);
pollerThread.setDaemon(true);
pollerThread.start();
}
Poller
事件队列中。protected int acceptorThreadCount = 1; protected void startAcceptorThreads() { int count = getAcceptorThreadCount(); acceptors = new ArrayList<>(count); for (int i = 0; i < count; i++) { Acceptor<U> acceptor = new Acceptor<>(this); String threadName = getName() + "-Acceptor-" + i; acceptor.setThreadName(threadName); acceptors.add(acceptor); Thread t = new Thread(acceptor, threadName); t.setPriority(getAcceptorThreadPriority()); t.setDaemon(getDaemon()); t.start(); } }
放一张Endpoint启动完之后主要的线程状态图。
从图中可以看出Acceptor Thread
和ClientPoller Thread
都处于running状态,而线程池则是wait状态,这里当ClientPoller Thread
接收到socket请求时,会启用线程池处理servlet请求。
到这里Tomcat就成功启动完成了。
参考:
https://blog.csdn.net/Dwade_mia/article/details/79244157
https://blog.csdn.net/Dwade_mia/article/details/79328151
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。