而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 / /
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