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. 深入学习 History 对象管理浏览器会话历史

    History对象允许我们操作浏览器会话历史,即加载当前页面的标签页窗口或frame窗口的访问历史.之前有同学咨询我如何实现拦截用户跳转页面并强制用户返回首页后重新请求页面,于是有了本篇博客的主题,本 ...

  2. 谈谈 CSS 关键字 initial、inherit 和 unset

    开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...

  3. Index column size too large. The maximum column size is 767 bytes.

    mysql建表时报Index column size too large. The maximum column size is 767 bytes.解决办法:在建表语句的后面加入:ENGINE=In ...

  4. FORM-加载前指定日期时间格式

    PRE-FORM -- Standard date format --BEGIN  set_application_property(DATE_FORMAT_COMPATIBILITY_MODE, ' ...

  5. IngressController的session stick问题

    周末爬坑,IngressController恢复因为镜像下载和版本问题折腾一下午,晚上终于折腾出个眉目. 首先,在Kubernetes的service中是可以设置Session Affinity的.例 ...

  6. [转]使用VS2010的Database 项目模板统一管理数据库对象

    本文转自:http://www.cnblogs.com/shanyou/archive/2010/05/08/1730810.html Visual Studio 2010 有一个数据库项目模板:Vi ...

  7. Nginx负载均衡+监控状态检测

    Nginx负载均衡+监控状态检测 想用Nginx或者Tengine替代LVS,即能做七层的负载均衡,又能做监控状态检测,一旦发现后面的realserver挂了就自动剔除,恢复后自动加入服务池里,可以用 ...

  8. BEA公司的weblogic是什么?有什么特点?

    转自:http://zhidao.baidu.com/link?url=J9obKwHhuh1sdLoBC3pILeaq1nz_tcpScggBNeS3D0GzAz9FI002vlS2xxJD4_z6 ...

  9. 服务端REST与SOAP的探讨

    REST简介 在开始我们的正式讨论之前,让我们简单看一下REST的定义. REST(Representational State Transfer)是Roy Fielding提出的一个描述互联系统架构 ...

  10. 一个简单的int型C++单链表的实现

    IntSLList.h //************************ intSLList.h ************************** // singly-linked list ...