还是继续看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基本的东西就算是介绍的差不多了吧。。。
接下来就可以继续深入这部分的类容了。。。