tomcat阅读第九篇(tomcat組件之Container和Engine)
上篇分析Service我们知道,在Service中主要涉及到Connector和Engine,我们先走Engine这条线,因为这涉及到tomcat内部工作机制,Connector是涉及到http与我们tomcat的连接,这个也是重点以后分析,这篇开始我们将进入Container系统组件,首先要看的Engine,下图是Engine的继承关系。
从上图可以比较清晰的看出StandardEngine的继承关系,所以看Engine组件之前,要大概的看下接口Container和抽象类ContainerBase。
Container接口主要方法:
//接口继承了Lifecycle接口 public interface Container extends Lifecycle { //addChild事件,添加的listner可以监听 public static final String ADD_CHILD_EVENT = "addChild"; //addValve事件,这个valve是很重要的存在,将来分析tomcat执行http请求流程的时候会重点涉及到 public static final String ADD_VALVE_EVENT = "addValve"; // removeChild事件 public static final String REMOVE_CHILD_EVENT = "removeChild"; // removeValve事件 public static final String REMOVE_VALVE_EVENT = "removeValve"; ……………………….. //这个Pipleline是valve的集合,将来分析tomcat解析请求的时候会重点分析 public Pipeline getPipeline(); //cluster涉及到集群,这个后面也会重点分析 public Cluster getCluster(); public void setCluster(Cluster cluster); //BackgroundProcessorDelay 标记后台任务多久执行一次,如果为负数,child的backgroundProccess都不会被执行 public int getBackgroundProcessorDelay(); public void setBackgroundProcessorDelay(int delay); …………………. //realm也是tomcat提供的一个机制,将来会重点分析 public Realm getRealm(); public void setRealm(Realm realm); // --------------------------------------------------------- Public Methods //执行一个周期性的任务在后台 public void backgroundProcess(); //下面都是跟child和listener相关的方法 public void addChild(Container child); public void addContainerListener(ContainerListener listener); public void addPropertyChangeListener(PropertyChangeListener listener); public Container findChild(String name); public Container[] findChildren(); public ContainerListener[] findContainerListeners(); public void removeChild(Container child); public void removeContainerListener(ContainerListener listener); public void removePropertyChangeListener(PropertyChangeListener listener); public void fireContainerEvent(String type, Object data); …………. //StartStopThreads? public int getStartStopThreads(); public void setStartStopThreads(int startStopThreads); ………….. }
ContainerBase 类:
从上面继承关系可以看出ContainerBase最终还是实现了LifeCycle,所以我们要重点看的是XXXXInternal几个回调方法,看源码可以发现很多addXXX,get/setXXX方法,从前面的分析我们可以知道这些基本上是Digester解析的时候需要调用的方法。
initInternal 方法:
//总的来说就是实例化startStopExecutor给后面的调用做准备 protected void initInternal() throws LifecycleException { BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>(); startStopExecutor = new ThreadPoolExecutor( getStartStopThreadsInternal(), getStartStopThreadsInternal(), 10, TimeUnit.SECONDS, startStopQueue, new StartStopThreadFactory(getName() + "-startStop-")); startStopExecutor.allowCoreThreadTimeOut(true); super.initInternal(); }
startInternal 方法:
// synchronized? protected synchronized void startInternal() throws LifecycleException { ………………… //获得Digester解析得到的Cluster,并启动 Cluster cluster = getClusterInternal(); if (cluster instanceof Lifecycle) { ((Lifecycle) cluster).start(); } //获得Digester解析得到的Realm,并启动 Realm realm = getRealmInternal(); if (realm instanceof Lifecycle) { ((Lifecycle) realm).start(); } //通过刚才实例化的Executor多线程的来启动child 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]))); } //利用Future特性进行失败处理 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")); } //启动pipleline中的valve if (pipeline instanceof Lifecycle) ((Lifecycle) pipeline).start(); setState(LifecycleState.STARTING); //后面分析 threadStart(); }
现在看下threadStart 方法:
protected void threadStart() { if (thread != null) return; //当backgroundProcessorDelay为负数不进行线程调用 if (backgroundProcessorDelay <= 0) return; //重要标志,标记什么时候不执行ContainerBackgroundProcessor threadDone = false; //设置thread name,设置为Daemon线程,线程内容是ContainerBackgroundProcessor类, String threadName = "ContainerBackgroundProcessor[" + toString() + "]"; thread = new Thread(new ContainerBackgroundProcessor(), threadName); thread.setDaemon(true); thread.start(); }
ContainerBackgroundProcessor类:
看源码可以知道处理的是子container的backgroundProcess方法。
stopInternal和destroyInternal方法就是相对应的按大概相反的顺序调用realm ,cluster相对应的stop 、destroy方法。
现在可以开始看Engine了,跟之前一样我们从Catalina的createStartDigester开始来看init过后StandardEngine的对象链以及Server.xml中关于Engine的配置。
上篇我们知道关于Engine的rule是EngineRuleSet。
EngineRuleSet 类:
重点是看addRuleInstances 方法
//解析到Engine标签的时候,创建StandardEngine对象 digester.addObjectCreate(prefix + "Engine", "org.apache.catalina.core.StandardEngine", "className"); //设置Engine标签相对应属性给StandardEngine对象 digester.addSetProperties(prefix + "Engine"); //如果Engine标签设置了engineConfigClass属性值,将实例化然后add给engine的LifeCyecleListener,没有设置就默认用EngineConfig类 digester.addRule(prefix + "Engine", new LifecycleListenerRule ("org.apache.catalina.startup.EngineConfig", "engineConfigClass")); //调用Service的setContainer方法,参数为StandardEngine digester.addSetNext(prefix + "Engine", "setContainer", "org.apache.catalina.Engine"); //解析到Engine/Cluster,通过标签上的className属性值实例化Cluster对象 digester.addObjectCreate(prefix + "Engine/Cluster", null, "className"); //设置Cluster标签上相对应的属性值进Cluster对象 digester.addSetProperties(prefix + "Engine/Cluster"); //调用Engine的setCluster方法,参数是Cluster对象 digester.addSetNext(prefix + "Engine/Cluster", "setCluster", "org.apache.catalina.Cluster"); //同之前解析Listener digester.addObjectCreate(prefix + "Engine/Listener", null, "className"); digester.addSetProperties(prefix + "Engine/Listener"); digester.addSetNext(prefix + "Engine/Listener", "addLifecycleListener", "org.apache.catalina.LifecycleListener"); //根据RealmRuleSet规则设置StandardEngine digester.addRuleSet(new RealmRuleSet(prefix + "Engine/")); //解析到Engine/Valve标签是通过标签上className属性创建valve对象 digester.addObjectCreate(prefix + "Engine/Valve", null, "className"); //设置标签上相对应属性进Valve digester.addSetProperties(prefix + "Engine/Valve"); //调用StandardEngine上的addValve方法,参数是实现Valve的对象,这个Valve将添加进container的Pipeline,这个Pipeline是tomcat解析请求流程的重要一员,后面会详细分析。 digester.addSetNext(prefix + "Engine/Valve", "addValve", "org.apache.catalina.Valve");
跟之前一样,看StandardEngine ,主要关注XXXInternal几个方法,因为它同时也是Container,所以还要关注另外跟Container相关的方法
看具体方法之前我们先看下Engine接口
public interface Engine extends Container { //Engine下默认的childhost public String getDefaultHost(); public void setDefaultHost(String defaultHost); //跟cluster相关的Engine都要有个jvmroute public String getJvmRoute(); public void setJvmRoute(String jvmRouteId); //我们的Service public Service getService(); public void setService(Service service); }
现在看StandardEngine 相关方法,观察源码,发现XXXInternal不是重点,重点是StandardEngine 的构造方法
public StandardEngine() { super(); //设置pipleline的basicValve为StandardEngineValve,后面大概看下StandardEngineValve类,valve类主要是在处理请求的过程中发挥作用 pipeline.setBasic(new StandardEngineValve()); try { //设置JvmRoute setJvmRoute(System.getProperty("jvmRoute")); } catch(Exception ex) { log.warn(sm.getString("standardEngine.jvmRouteFail")); } //设置backgroundProcessorDelay为10,表明Engine会启动线程每隔10×1000 s 来调用它的child的backgroudProcess backgroundProcessorDelay = 10; }
initInternal 方法:
protected void initInternal() throws LifecycleException { //确保realm被设置,如果没有配置,设置NullRealm getRealm(); super.initInternal(); } startInternal 方法: protected synchronized void startInternal() throws LifecycleException { //记log if(log.isInfoEnabled()) log.info( "Starting Servlet Engine: " + ServerInfo.getServerInfo()); super.startInternal(); }
Valve和Pipeline有必要单独分析,涉及到tomcat请求流程的处理。
总结:这篇开始就进入了tomcat的相对核心的部分,新的Container继承链,跟Container相关的有几个重要的类,Valve和Pipeline、Cluster、Realm,都是tomcat提供的一些相对应的特性,后面会有单独分析,每个不同的Container重点在于他们想对应的Valve,渐渐进入核心,目前我们只关注tomcat的启动和停止,关于Valve和Pipeline的分析我们只是介绍方便后面Container的介绍,关于流程的处理后面会专门大篇幅分析,流程的处理的代码比较复杂。