还是继续看Tomcat的源码吧,前面分析过了在tomcat中比较重要的一个东西Connector部分。。。
先来看一张图:
可以将tomcat的结构大概这样描述吧:
(1)sever对象是service对象的容器,
(2)service对象是connector对象和container对象的容器,同一个service对象可以包含多个connector对象,但是只能包含一个container对象。。。
(3)container对象是属于自包含的,自己又可以包含多个子container对象,
(4)同时container对象包含一个pipeline对象,pipeline对象可以理解为是valve对象的容器。。。
这里先来贴一下container接口的实现吧:
//主要是定义了父子container的管理以及pipeline的管理 public interface Container extends Lifecycle { //一些基本的事件的定义 public static final String ADD_CHILD_EVENT = "addChild"; //添加了child的事件 public static final String ADD_VALVE_EVENT = "addValve"; //在pipeline上面添加了valve的事件 public static final String REMOVE_CHILD_EVENT = "removeChild"; //移除child的事件 public static final String REMOVE_VALVE_EVENT = "removeValve"; //移除valve的事件 public Log getLogger(); //用于在jmx上面注册的名字 public ObjectName getObjectName(); public String getDomain(); public String getMBeanKeyProperties(); //pipeline,用于管理关联的values public Pipeline getPipeline(); //返回关联的cluster public Cluster getCluster(); public void setCluster(Cluster cluster); //后台运行的延迟 public int getBackgroundProcessorDelay(); void setBackgroundProcessorDelay(int delay); //当前container对象的名字 public String getName(); public void setName(String name); //返回父container public Container getParent(); //设置父container public void setParent(Container container); //获取父classLoader,如果当前没有的话,如果有parent那么返回parent的,否则返回applicationclassloader public ClassLoader getParentClassLoader(); public void setParentClassLoader(ClassLoader parent); //返回realm对象,如果当前container对象没有的话,那么返回parent的realm对象 public Realm getRealm(); public void setRealm(Realm realm); // --------------------------------------------------------- Public Methods // 在后台执行一些周期性的工作 public void backgroundProcess(); //添加child对象 public void addChild(Container child); // 添加listener对象,用于响应当前container对象的事件 public void addContainerListener(ContainerListener listener); //添加属性改变的listener public void addPropertyChangeListener(PropertyChangeListener listener); //根据名字返回子child public Container findChild(String name); //返回所有的child public Container[] findChildren(); //返回所有的containerlistener对象 public ContainerListener[] findContainerListeners(); //移除一个child对象 public void removeChild(Container child); //移除一个containerlistener对象 public void removeContainerListener(ContainerListener listener); //移除一个属性监听器 public void removePropertyChangeListener(PropertyChangeListener listener); //触发容器的事件,这里主要是调度listener对象 public void fireContainerEvent(String type, Object data); public void logAccess(Request request, Response response, long time, boolean useDefault); public AccessLog getAccessLog(); //用于启动,停止子container对象的线程数量 public int getStartStopThreads(); //设置用于启动或者停止子container对象的线程数量 public void setStartStopThreads(int startStopThreads); public File getCatalinaBase(); }
这里接口虽然还挺长的,但是实际上要做的主要的事情就是对子container对象的管理吧,例如添加或者移除子container对象。。另外就还有一些listener对象的管理了,这里分为两种listener吧,首先是事件的listener,例如添加child,添加valve事件的listener,另外就还有一种属性的listener,当属性发生改变的时候会响应。。。
好了,接下来介绍ContainerBase类型吧,先来看看它简略的继承体系吧:
这里首先是继承了LifecycleMBeanBase类型,说明对于Container对象,它的启动将会在JMX上面进行注册。。。
接着是实现了Container接口。。。
这里就不贴ContainerBase的具体实现了。。。
先来看看他的一些重要的属性定义吧:
protected final HashMap<String, Container> children = new HashMap<>(); //用于保存子container,key是子container对象的名字 protected final List<ContainerListener> listeners = new CopyOnWriteArrayList<>(); //listener,是一个写时复制的 protected ClassLoader parentClassLoader = null; //父classLoader /** * The Pipeline object with which this Container is associated. */ protected final Pipeline pipeline = new StandardPipeline(this); //pipeline对象 protected final PropertyChangeSupport support = //用于管理属性的更改情况 new PropertyChangeSupport(this);
首先是children对象,它是hashmap类型的,用于记录当前container对象的所有的child对象,key是child的名字,value就是具体的child对象了。。。
接着是两种类型的listener,一个用于监听事件,一个用于监听属性的改变。。。这里先来看看addChild方法吧,用于添加子container对象:
//加入child对象 public void addChild(Container child) { if (Globals.IS_SECURITY_ENABLED) { PrivilegedAction<Void> dp = new PrivilegedAddChild(child); AccessController.doPrivileged(dp); } else { addChildInternal(child); } } //加入child private void addChildInternal(Container child) { if( log.isDebugEnabled() ) log.debug("Add child " + child + " " + this); synchronized(children) { if (children.get(child.getName()) != null) //看是否有重名的host throw new IllegalArgumentException("addChild: Child name ‘" + child.getName() + "‘ is not unique"); child.setParent(this); // May throw IAE //设置当前child的父亲是当前对象 children.put(child.getName(), child); //将名字与child对应起来 } // Start child // Don‘t do this inside sync block - start can be a slow process and // locking the children object can cause problems elsewhere if ((getState().isAvailable() || //如果当前已经运行了,那么启动child LifecycleState.STARTING_PREP.equals(getState())) && startChildren) { try { child.start(); //看情况启动当前加入的child } catch (LifecycleException e) { log.error("ContainerBase.addChild: start: ", e); throw new IllegalStateException ("ContainerBase.addChild: start: " + e); } } fireContainerEvent(ADD_CHILD_EVENT, child); //激活相应的事件的listener }
这里还是比较简单吧,无非就是将其放入刚刚说的map里面,然后再根据当前的一些配置是否启动刚刚加入的子container对象就好了。。。接着再激活添加child的事件就好了,让相应的listener对象来响应。。。。
接下来再来看看初始化已经启动的方法吧:
@Override protected void initInternal() throws LifecycleException { BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>(); //启动,停止任务的队列 startStopExecutor = new ThreadPoolExecutor( //用到的executor对象 getStartStopThreadsInternal(), getStartStopThreadsInternal(), 10, TimeUnit.SECONDS, startStopQueue, new StartStopThreadFactory(getName() + "-startStop-")); startStopExecutor.allowCoreThreadTimeOut(true); super.initInternal(); } /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override //这里主要是启动child,还有pipeline,以及cluster对象 protected synchronized void startInternal() throws LifecycleException { // Start our subordinate components, if any logger = null; getLogger(); Cluster cluster = getClusterInternal(); if ((cluster != null) && (cluster instanceof Lifecycle)) ((Lifecycle) cluster).start(); Realm realm = getRealmInternal(); if ((realm != null) && (realm instanceof Lifecycle)) ((Lifecycle) realm).start(); // Start our child containers, if any Container children[] = findChildren(); //获取所有的child List<Future<Void>> results = new ArrayList<>(); for (int i = 0; i < children.length; i++) { //启动所有的child results.add(startStopExecutor.submit(new StartChild(children[i]))); } 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 if (pipeline instanceof Lifecycle) ((Lifecycle) pipeline).start(); //启动pipeline对象 setState(LifecycleState.STARTING); // Start our thread threadStart(); //启动background线程,执行一些周期事物 }
这里初始化主要是在创建executor对象,比较奇怪,container对象在启动子container对象的时候并不是在当前线程中运行,而是将其派发到executor里面运行。。。
启动的方法,其实主要就是启动pipeline对象,启动所有的child,以及cluster。。。。
好啦,Container就先到这把,嗯,简单的理解为,它是container的容器,而且管理了pipeline对象。。。还有cluster啥的。。。。
好啦,接下来来看pipeline对象了。。。在具体的看它之前呢,得要先知道valve是干啥的才行。。。毕竟pipeline对象可以理解为valve对象的容器。。。。而且其的工作就是依靠valve对象来进行的。。。
那么就来看看valve接口的定义吧:
//value对象是与container相关联的处理请求的组件,一系列的value组成了pipeline public interface Valve { public Valve getNext(); //返回pipeline的下一个value对象,在pipeline上面,valve对象组成了一个链表 public void setNext(Valve valve); //设置下一个value对象 //执行一些周期的工作 public void backgroundProcess(); //处理request与response public void invoke(Request request, Response response) throws IOException, ServletException;
//处理comet事件 public void event(Request request, Response response, CometEvent event) throws IOException, ServletException; //是否支持异步 public boolean isAsyncSupported(); }
嗯,这里接口的定义还算是比较的简单吧,其实说白了container对象依靠pipeline对象来处理请求,而pipeline对象则是依赖valve对象来处理请求的。。。
这里比较重要的就是invoke方法了,具体的来处理http请求。。。。
好啦,来看Pipeline接口的定义吧:
//pipeline的接口定义 public interface Pipeline { //返回basic的value public Valve getBasic(); //这是basic的value public void setBasic(Valve valve); //在pipeline的末端添加一个value对象 public void addValve(Valve valve); //返回value对象的数组 public Valve[] getValves(); //移除一个value对象 public void removeValve(Valve valve); //获取pipeli的第一个value对象 public Valve getFirst(); //是否支持异步,这里如果当前pipeline上面的所有valve都支持异步才能说当前pipeline支持异步 public boolean isAsyncSupported(); //返回所属的container public Container getContainer(); //设置container对象 public void setContainer(Container container); }
这里其实接口定义的还蛮简单的,接单的理解,pipeline维护了一个valve对象组成的链表,同时它还有一个特殊的valve对象,那就是basic。。。
接下来看StandardPipeline的定义吧,嗯,由于代码比较长,就不贴出来了。。来看它的重要的属性定义吧:
/** * The basic Valve (if any) associated with this Pipeline. */ protected Valve basic = null; //basic的valve对象,如果有普通valve对象的话,basic对象将会处在链表的尾部 /** * The Container with which this Pipeline is associated. */ protected Container container = null; //拥有这个pipeline的container对象 /** * The first valve associated with this Pipeline. */ protected Valve first = null; //valve链表的头
嗯,首先是basic的valve引用,接着是当前pipeline相关联的container对象。。。最后就是说的valve链表的头部引用了。。。
这里来看几个比较基本的方法吧:
//这里其实是启动所有的valve对象,如果它实现了lifecycle接口的话 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; } while (current != null) { if (current instanceof Lifecycle) ((Lifecycle) current).start(); current = current.getNext(); } setState(LifecycleState.STARTING); }
启动,其实主要是启动内部的valve对象,如果valve对象实现了lifecycle接口的话。。。
//添加valve对象,添加到队列的尾部,但其实是在basic的前面 public void addValve(Valve valve) { // Validate that we can add this Valve if (valve instanceof Contained) ((Contained) valve).setContainer(this.container); // Start the new component if necessary if (getState().isAvailable()) { if (valve instanceof Lifecycle) { try { ((Lifecycle) valve).start(); //启动 } catch (LifecycleException e) { log.error("StandardPipeline.addValve: start: ", e); } } } // Add this Valve to the set associated with this Pipeline //如果啥都没有,那么直接first if (first == null) { first = valve; valve.setNext(basic); //first后面指向basic } else { Valve current = first; while (current != null) { //将这里擦到最后,然后将新插入的valve指向basic,其实basic才是队列的尾部 if (current.getNext() == basic) { current.setNext(valve); valve.setNext(basic); break; } current = current.getNext(); } } container.fireContainerEvent(Container.ADD_VALVE_EVENT, valve); }
这里添加valve对象的方法,主要就是将要添加的valve对象放到链表的尾部,同时要保证它的next指向basic对象。。同时有需要的话还要启动它,最后还要激活相应的container上面的事件。。。
好啦。。。到这里,container以及pipeline基本的东西就算是介绍的差不多了吧。。。
接下来就可以继续深入这部分的类容了。。。
Tomcat源码阅读之Container与Pipeline的设计,布布扣,bubuko.com
Tomcat源码阅读之Container与Pipeline的设计
原文:http://blog.csdn.net/fjslovejhl/article/details/20713005