1. 描述

Container提供管理bean的能力。

基于Jetty-9.4.8.v20171121。

1.1 API

public interface Container
{
// 增加一个bean,如果bean是一个Container.Listener则隐含调用addEventListener(Container.Listener)方法
// Container.Listener只关心两个事件:(1)增加bean(2)删除bean
public boolean addBean(Object o); // 返回该Container里面所有的bean
public Collection<Object> getBeans(); // 返回指定类型(包括子类)的bean
public <T> Collection<T> getBeans(Class<T> clazz); // 返回指定类型(包括子类)的第一个bean,如果不存在则返回null
public <T> T getBean(Class<T> clazz); // 删除指定的bean,如果bean是一个Container.Listener,隐含调用removeEventListener(Container.Listener)
public boolean removeBean(Object o); // 增加一个Listener
public void addEventListener(Listener listener); // 删除一个Listener
public void removeEventListener(Listener listener); // 未托管一个bean(必须已经存在在Container里面),所以该bean不应该启动,停止或销毁
void unmanage(Object bean); // 托管一个bean(必须已经存在在Container里面),所以该bean已启动,已停止或销毁
void manage(Object bean); // 检测该Container是否托管一个bean
boolean isManaged(Object bean); // 增加一个bean,并且明确是否托管(即是否管理该bean的生命周期)
// 如果已经增加返回true,如果已经存在返回false
boolean addBean(Object o, boolean managed); // Container事件的监听器
// 如果一个增加的bean实现该接口将会收到该Container的事件
public interface Listener
{
void beanAdded(Container parent,Object child);
void beanRemoved(Container parent,Object child);
} /**
* Inherited Listener.
* If an added bean implements this interface, then it will
* be added to all contained beans that are themselves Containers
* 如果增加的bean实现该接口,则将该bean增加到当前Container里面所有bean类型为Container里面。
*/
public interface InheritedListener extends Listener
{
} /**
* @param clazz the class of the beans
* @return the list of beans of the given class from the entire managed hierarchy
* @param <T> the Bean type
*/
public <T> Collection<T> getContainedBeans(Class<T> clazz);
}  

从API可以看出Container主要维护bean并且监听bean的增加和删除事件。

1.2 类图

从类图可以看出,Container与LifeCycle接口很类似,都是很多组件的基本特征,其默认实现是ContainerLifeCycle。

2. ContainerLifeCycle

1.2类图可以看出ContainerLifeCycle不仅是Container的默认实现,而且也是很多组件(Connector,Handler等)默认实现的父类。

2.1 类图

ContainerLifeCycle自然要实现Container接口;

ContainerLifeCycle继承AbstractLifeCycle,而AbstractLifeCycle里面实现了LifeCycle的模板启停方法start和stop;

继承AbstractLifeCycle的子类只需要实现AbstractLifeCycle中增加的doStart和doStop实现子类具体的启动和停止,具体请参考【Jetty - LifeCycle源码分析】

ContainerLifeCycle.Bean:内部类,表示管理的Bean对象。

ContainerLifeCycle.Managed:内部类,被管理的Bean有几种类型:POJO,MANAGED,UNMANAGED,AUTO。

2.2 doStart和doStop

启动主要分为如下两个步骤:

(1)设置标志位_doStart = true;

(2)启动具有生命周期的bean(a)如果托管bean并且未运行的,则启动(b)如果是自动bean并且运行中,则设置为未托管;未运行的,则设置为托管,并且启动;

    // 以添加的顺序启动托管的bean
@Override
protected void doStart() throws Exception
{
if (_destroyed)
throw new IllegalStateException("Destroyed container cannot be restarted"); // 标示已经启动,addBean可以启动其他的bean
_doStarted = true; // 启动托管和自动beans
for (Bean b : _beans) // 遍历所有bean
{
if (b._bean instanceof LifeCycle)
{
LifeCycle l = (LifeCycle)b._bean;
switch(b._managed)
{
case MANAGED: // 如果是托管bean,并且未运行,则启动
if (!l.isRunning())
start(l);
break;
case AUTO: // 如果是自动bean
if (l.isRunning()) // 如果已经运行了,则设置为未托管
unmanage(b);
else // 如果未运行,设置为托管,并且启动
{
manage(b);
start(l);
}
break;
}
}
}
// 此处调用父类的doStart方法,就是AbstractLifeCycle的doStart方法,其实是个空实现
super.doStart();
}  

停止主要分为两个步骤:

(1)设置标志位;

(2)逆序停止具有生命周期的托管bean,为什么逆序?主要与启动顺序比较,防止bean之间有关联出现错误,类似资源释放。

    // 以添加的逆序停止具有生命周期的托管bean
@Override
protected void doStop() throws Exception
{
_doStarted = false; // 设置停止状态位
super.doStop(); // 调用AbstractLifeCycle的doStop方法,其实是个空方法
List<Bean> reverse = new ArrayList<>(_beans);
Collections.reverse(reverse); // 逆序
for (Bean b : reverse)
{ // 具有生命周期并且托管的bean
if (b._managed==Managed.MANAGED && b._bean instanceof LifeCycle)
{
LifeCycle l = (LifeCycle)b._bean;
stop(l);
}
}
}  

2.3 addBean

// o:bean,managed:bean类型
// 注意基本原则:在ContainerLifeCycle类里面有两个字段_beans和_listener,如果添加的bean也是Container.Listener类型,则需要在_listener里面也增加一个
public boolean addBean(Object o, Managed managed)
{
if (o==null || contains(o)) // 如果bean为null或者已经存在
return false; Bean new_bean = new Bean(o); // 包装为Bean对象 // 如果bean是Container.Listener
if (o instanceof Container.Listener)
addEventListener((Container.Listener)o); // 添加bean
_beans.add(new_bean); // 通知所有_listeners,有新bean添加的事件
for (Container.Listener l:_listeners)
l.beanAdded(this,o); try
{
switch (managed)
{
case UNMANAGED:
unmanage(new_bean);
break; case MANAGED:
manage(new_bean);
// 如果ContainerLifeCycle在启动中,即调用doStart还没有退出
if (isStarting() && _doStarted)
{ // 此处o是一个任意类型且是个public方法,此处直接转为LifeCycle是否有问题?
LifeCycle l = (LifeCycle)o;
// 为什么有这样的判断?
// doStart的过程(1)设置状态位(2)以bean添加的顺序启动具有生命周期的bean,如果此时调用了addBean有可能同步的问题,导致新添加的bean没有通过doStart启动,所以需要在此处判断如果未启动,则启动一下
if (!l.isRunning())
start(l);
}
break; case AUTO:
if (o instanceof LifeCycle)
{
LifeCycle l = (LifeCycle)o;
if (isStarting()) // 如果ContainerLifeCycle启动中
{
if (l.isRunning()) // 如果bean运行中,则设置为未托管,不需要ContainerLifeCycle管理启动
unmanage(new_bean);
else if (_doStarted) // 如果bean未运行,并且ContainerLifeCyle启动中,则设置为托管bean并且启动之
{
manage(new_bean);
start(l);
}
else
new_bean._managed=Managed.AUTO;
}
else if (isStarted()) // 如果ContainerLifeCycle已经启动
unmanage(new_bean);
else // ContainerLifeCycle未启动
new_bean._managed=Managed.AUTO;
}
else
new_bean._managed=Managed.POJO;
break; case POJO:
new_bean._managed=Managed.POJO;
}
}
catch (RuntimeException | Error e)
{
throw e;
}
catch (Exception e)
{
throw new RuntimeException(e);
} if (LOG.isDebugEnabled())
LOG.debug("{} added {}",this,new_bean); return true;
}
// 删除bean
private boolean remove(Bean bean)
{
if (_beans.remove(bean))
{
boolean wasManaged = bean.isManaged(); // bean是否是托管类型 unmanage(bean); // 设置bean为未托管类型 for (Container.Listener l:_listeners) // 通知监听器
l.beanRemoved(this,bean._bean);
// 如果被remove的bean是Listener,需要调用removeEventListener
if (bean._bean instanceof Container.Listener)
removeEventListener((Container.Listener)bean._bean); // 如果是具有生命周期托管的bean需要停止。
if (wasManaged && bean._bean instanceof LifeCycle)
{
try
{
stop((LifeCycle)bean._bean);
}
catch(RuntimeException | Error e)
{
throw e;
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
return true;
}
return false;
}

2.4 插播Container管理bean的规则

通过前面的doStart和addBean可以基本确定Container管理bean的如下几条规则:

ContainerLifeCycle是对容器化bean组件的一个生命周期的实现。

bean可以作为托管bean或未托管bean放入ContainerLifeCycle里面。

托管bean的启动停止和销毁由ContainerLifeCycle控制;未托管主要是为了dump,它们的生命周期必须独立管理。

当一个没有指定类型具有生命周期的bean加入到ContainerLifeCycle,ContianerLifeCycle可以推断它的类型:

(1)如果增加的bean运行中,它将以未托管类型加入container;

(2)如果增加的bean未运行且container也未运行,它将以AUTO类型加入container;

(3)如果增加的bean未运行且container在启动中,它将以托管类型加入container;

(4)如果增加的bean未运行且container已经启动,它将以未托管类型加入container;

当container已经启动,所有的托管bean也应该启动。

任何AUTO类型的bean都将依据它们的状态被分为托管或未托管,如果已经启动则为未托管,否则将启动它们然后设置为托管类型。

Contianer启动之后添加的bean将不会被启动,它们的状态需要显式管理。

当停止Container的时候,只有被这个Container启动的bean才会停止。

如果一个bean被多个Container共享,那么该bean只能是未托管的,即在增加之前,应该被启动

2.4.1 实例

2.5 manage和unmanage

manage是设置bean为托管类型,unmanage设置bean为未托管类型。

可以理解为两个相反的操作,需要注意如果被设置的bean是个Container,则需要将当前_listeners里面所有类型为InheritedListener的监听器添加到该bean里面或从该bean里面移除。

// 托管bean
private void manage(Bean bean)
{
if (bean._managed!=Managed.MANAGED)
{
bean._managed=Managed.MANAGED; // 设置bean为托管 if (bean._bean instanceof Container)
{
for (Container.Listener l:_listeners)
{
if (l instanceof InheritedListener) // 如果当前bean的listener里面有是InheritedListener需要增加到bean的_beans列表中
{
if (bean._bean instanceof ContainerLifeCycle)
((ContainerLifeCycle)bean._bean).addBean(l,false);
else
((Container)bean._bean).addBean(l);
}
}
} if (bean._bean instanceof AbstractLifeCycle)
{
((AbstractLifeCycle)bean._bean).setStopTimeout(getStopTimeout());
}
}
}
// 未托管bean
private void unmanage(Bean bean)
{
if (bean._managed!=Managed.UNMANAGED)
{
if (bean._managed==Managed.MANAGED && bean._bean instanceof Container)
{
for (Container.Listener l:_listeners)
{ // 如果监听器是InheritedListener,需要将其从未托管的bean中移除
if (l instanceof InheritedListener)
((Container)bean._bean).removeBean(l);
}
}
bean._managed=Managed.UNMANAGED;
}
}

  

2.6 addEventListener和removeEventListener

两个是相反的操作,一个是增加Listener,另一个是删除Listener。

如果待操作的Listener是InheritedListener子类,需要级联操作。

@Override
public void addEventListener(Container.Listener listener)
{
if (_listeners.contains(listener))
return; _listeners.add(listener); // 新加的Listener需要被告知所有bean
for (Bean b:_beans)
{
listener.beanAdded(this,b._bean); // 如果是InheritedListener需要增加到bean为Container的_beans列表中
if (listener instanceof InheritedListener && b.isManaged() && b._bean instanceof Container)
{
if (b._bean instanceof ContainerLifeCycle)
((ContainerLifeCycle)b._bean).addBean(listener, false);
else
((Container)b._bean).addBean(listener);
}
}
}
  @Override
public void removeEventListener(Container.Listener listener)
{
if (_listeners.remove(listener))
{
// remove existing beans
for (Bean b:_beans)
{
listener.beanRemoved(this,b._bean);
// 与增加相反,需要级联移除
if (listener instanceof InheritedListener && b.isManaged() && b._bean instanceof Container)
((Container)b._bean).removeBean(listener);
}
}
}  

2.7 updateBean  

最后ContainerLifeCycle还提供了重载的updateBean,入参一般是一个老bean和一个新bean。

一般操作都是先删除老bean,然后增加新bean,都是复用上面提到的removeBean和addBean,不在详细描述。

Jetty - Container源码分析的更多相关文章

  1. Jetty - Connector源码分析

    1. 描述 基于Jetty-9.4.8.v20171121. Connector接受远程机器的连接和数据,允许应用向远程机器发送数据. 1.2 类图 从类图看出AbstractConnector继承C ...

  2. Jetty - LifeCycle源码分析

    1. 描述 基于Jetty-9.4.8.v20171121. LifeCycle主要管理Jetty里面通用组件的生命周期,比如组件启动中.启动.运行.停止中.停止等,实现该接口就可以定义一套生命周期. ...

  3. Jetty 9 源码分析 Connector及Server类(一)

    本文的源码基于Jetty9,主要分析了Jetty 的Connector与Server类间在Jetty启动过程中的一些细节.Jetty9 对以前的Connector体系进行了重构, 结构与6和7都不同, ...

  4. Spring IoC Container源码分析(二)-bean初始化流程

    准备 Person实例 @Data public class Person { private String name; private int age; } xml bean配置 <?xml ...

  5. Jetty - Handler源码分析

    1. 描述 基于Jetty-9.4.8.v20171121. Handler是Jetty服务处理器,用户Server处理HTTP请求. Handler可以做如下处理: (1)完全生成HTTP响应: ( ...

  6. jetty加载spring-context容器源码分析

    带着疑问开始 web.xml的顺序问题 先拿一个最简单的spring mvc web.xml来说问题,如下图:如果我将三者的顺序倒置或是乱置,会产生什么结果呢? 启动报错?还是加载未知结果?还是毫无影 ...

  7. Docker源码分析(八):Docker Container网络(下)

    1.Docker Client配置容器网络模式 Docker目前支持4种网络模式,分别是bridge.host.container.none,Docker开发者可以根据自己的需求来确定最适合自己应用场 ...

  8. Docker源码分析(七):Docker Container网络 (上)

    1.前言(什么是Docker Container) 如今,Docker技术大行其道,大家在尝试以及玩转Docker的同时,肯定离不开一个概念,那就是“容器”或者“Docker Container”.那 ...

  9. dubbox源码分析(一)-服务的启动与初始化

    程序猿成长之路少不了要学习和分析源码的.最近难得能静得下心来,就针对dubbox为目标开始进行源码分析. [服务提供方] 步骤 调用顺序 备注 容器启动 com.alibaba.dubbo.conta ...

随机推荐

  1. nand flash坏块管理OOB,BBT,ECC

    转:http://www.cnblogs.com/elect-fans/archive/2012/05/14/2500643.html 0.NAND的操作管理方式 NAND FLASH的管理方式:以三 ...

  2. Java_导出Excel

    导出的Excel标题.Sheet名称.数据内容都可以使用中文​ 一.pom.xml引入jar包 1 2 3 4 5 <dependency>             <groupId ...

  3. easyui-textbox input输入框的一种取值方式

    1.html文件 <td> <input id="clientPhone" type="text" name="clientPhon ...

  4. 配置安全证书的Etcd集群

    不知在哪篇技术文档中看到,kubernetes master和etcd分开部署模式,因为集群的状态都保存在etcd中,这样当kubernetes master挂掉后,通过API Server交互的Sc ...

  5. (C语言版)链表(四)——实现双向循环链表创建、插入、删除、释放内存等简单操作

    双向循环链表是基于双向链表的基础上实现的,和双向链表的操作差不多,唯一的区别就是它是个循环的链表,通过每个节点的两个指针把它们扣在一起组成一个环状.所以呢,每个节点都有前驱节点和后继节点(包括头节点和 ...

  6. 在Windows Server 2008 R2上安装Exchange 2013过程中遇到的一些问题

    笔者对Exchange经验非常有限, 但也正因为如此, 这里分享的东西对从没接触过Exchange的朋友会有更多的帮助吧, 至少希望如此.   1. Exchange 2013的安装需要.net fr ...

  7. pip安装scrapy时报错:error: Unable to find vcvarsall.bat

    网上一堆胡说八道的,请看微软官方文章: https://blogs.msdn.microsoft.com/pythonengineering/2016/04/11/unable-to-find-vcv ...

  8. MySQL分库备份与分表备份

    MySQL分库备份与分表备份 1.分库备份 要求:将mysql数据库中的用户数据库备份,备份的数据库文件以时间命名 脚本内容如下: [root@db01 scripts]# vim backup_da ...

  9. BST数据结构题

    给定BST.改动BST,使得每一个点都是大于他的结点的值之和 关键是这题递归參数怎么设计,每一个点比他大的有两快.一个是右子书(假设有的话),还有一个是祖先里面比他大的,假设直接用这两个的话,找不到递 ...

  10. iOS7重磅推新--不断尝试与重新设计的过程

    来源:GBin1.com iOS7重磅推新--不断尝试与重新设计的过程 或许你心里已经有了关于iPhone最新操作系统的评价,可能你喜欢它,也可能不喜欢,事实上大多数设计者不喜欢.设计界似乎一致认为I ...