Jetty - Container源码分析

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)删除beanpublic boolean addBean(Object o);// 返回该Container里面所有的beanpublic Collection<Object> getBeans();// 返回指定类型(包括子类)的beanpublic <T> Collection<T> getBeans(Class<T> clazz);// 返回指定类型(包括子类)的第一个bean,如果不存在则返回nullpublic <T> T getBean(Class<T> clazz);// 删除指定的bean,如果bean是一个Container.Listener,隐含调用removeEventListener(Container.Listener)public boolean removeBean(Object o);// 增加一个Listenerpublic void addEventListener(Listener listener);// 删除一个Listenerpublic void removeEventListener(Listener listener);// 未托管一个bean(必须已经存在在Container里面),所以该bean不应该启动,停止或销毁void unmanage(Object bean);// 托管一个bean(必须已经存在在Container里面),所以该bean已启动,已停止或销毁void manage(Object bean);// 检测该Container是否托管一个beanboolean 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@Overrideprotected void doStart() throws Exception{if (_destroyed)throw new IllegalStateException("Destroyed container cannot be restarted");// 标示已经启动,addBean可以启动其他的bean_doStarted = true;// 启动托管和自动beansfor (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: // 如果是自动beanif (l.isRunning()) // 如果已经运行了,则设置为未托管unmanage(b);else // 如果未运行,设置为托管,并且启动{manage(b); start(l);}break;}}}// 此处调用父类的doStart方法,就是AbstractLifeCycle的doStart方法,其实是个空实现super.doStart();}  

停止主要分为两个步骤:

(1)设置标志位;

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

    // 以添加的逆序停止具有生命周期的托管bean@Overrideprotected void doStop() throws Exception{  _doStarted = false; // 设置停止状态位super.doStop(); // 调用AbstractLifeCycle的doStop方法,其实是个空方法List<Bean> reverse = new ArrayList<>(_beans);Collections.reverse(reverse); // 逆序for (Bean b : reverse) {   // 具有生命周期并且托管的beanif (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.Listenerif (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);}elsenew_bean._managed=Managed.AUTO;      }else if (isStarted()) // 如果ContainerLifeCycle已经启动unmanage(new_bean);else // ContainerLifeCycle未启动new_bean._managed=Managed.AUTO;}elsenew_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,需要调用removeEventListenerif (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子类,需要级联操作。

@Overridepublic void addEventListener(Container.Listener listener){if (_listeners.contains(listener))return;_listeners.add(listener);// 新加的Listener需要被告知所有beanfor (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);}}}

 

  @Overridepublic void removeEventListener(Container.Listener listener){if (_listeners.remove(listener)){// remove existing beansfor (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,不在详细描述。 

转载于:https://www.cnblogs.com/lujiango/p/8361415.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/452849.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu中安装FastDFS

1 安装fastdfs依赖包 解压缩libfastcommon-master.zip进入到libfastcommon-master的目录中执行 ./make.sh执行 sudo ./make.sh install 2 安装fastdfs 解压缩fastdfs-master.zip进入到 fastdfs-master目录中执行 ./make.sh执行 sudo ./make.sh install 3 配置跟踪服务器tra…

python基本语句及其意思_Python语法基础(1),一

一、Python的对象模型对象是Python语言中最基本的概率&#xff0c;在Python中处理的一切都是对象。Python中许多内置对象可提供编程者使用&#xff0c;内置对象可直接使用&#xff0c;如数字、字符串、列表 、del等&#xff1b;非内置对象需要导入模块才能使用&#xff0c;如正…

什么是隧道技术

隧道技术是一种通过互联网络基础设施在网络之间传递数据的方式。使用隧道传递的数据可以是不同协议的数据帧或包&#xff0c;隧道协议将这些其它协议的数据帧或包重新封装在新的包头中发送&#xff0c;被封装的数据包在隧道的两个端点之间通过公共互联网络进行路由&#xff0c;…

详解网络数字电视的实现方法与关键技术

1、IPTV的实现方法 宽带网络数字电视&#xff0c;又称IPTV或BTV&#xff0c;即交互式网络电视&#xff0c;是一种利用宽带互联网、多媒体等多种技术于一体&#xff0c;向家庭用户提供包括数字电视在内的多种交互式服务的崭新技术。它能够很好地适应当今网络飞速发展的趋势&…

有状态的bean和无状态的bean的区别

有状态会话bean &#xff1a;每个用户有自己特有的一个实例&#xff0c;在用户的生存期内&#xff0c;bean保持了用户的信息&#xff0c;即“有状态”&#xff1b;一旦用户灭亡&#xff08;调用结束或实例结束&#xff09;&#xff0c;bean的生命期也告结束。即每个用户最初都会…

因为我想在博客园长呆,所以给博客园提一些改进建议

一晃眼我来博客园已经有4个月了&#xff0c;我的排名从9万多上升到9千多&#xff0c;也有不少朋友关注了我&#xff0c;其实对我帮助更大的是博客园的管理团队&#xff0c;他们对我的文章提出了很多很好的改进建议&#xff0c;从而让我的文章水平有了很大的提升。 这里我从用户…

double 二进制 java_C#中将double值变成二进制然后写入文件,Java中载入该文件读取此二进制double值时不正确...

目前已定位到是因为C#中的byte范围是0到255&#xff0c;而java中byte值为-128到127导致的错误。尝试过使用C#的sbyte来解决&#xff1a;bw1 new BinaryWriter(new FileStream("C:\\Users\\DELL\\Desktop\\SpatialIndex\\ctest1.bin", FileMode.Create));bw2 new Bi…

什么是移动IP

移动代理 &#xff08;Mobility Agent&#xff09;&#xff1a;又分为归属代理和外区代理两类。归属代理是归属网上的移动代理&#xff0c;它至少有一个接口在归属网上。其责任是当移动节点移动到外区网时&#xff0c;截收发往该点的数据包&#xff0c;并使用隧道技术将这些数据…

Ubuntu中安装nginxError

问题1&#xff1a;出现如下错误&#xff1a; ./configure: error: the HTTP rewrite module requires the PCRE library. You can either disable the module by using --without-http_rewrite_module option, or install the PCRE library into the system, or build the PCR…

项目经理如何把工作简单化

做一件事有两种方式。其一是把简单的事情复杂化&#xff0c;另外就是把复杂的事情简单化。项目经理应该如何选择呢?恐怕大家会异口同声的说&#xff0c;当然是把复杂的事情简单化。但是&#xff0c;在实际工作中&#xff0c;很少有项目经理能够做到这一点。他们会不知不觉中把…

[luogu P2590 ZJOI2008] 树的统计 (树链剖分)

题目描述 一棵树上有n个节点&#xff0c;编号分别为1到n&#xff0c;每个节点都有一个权值w。 我们将以下面的形式来要求你对这棵树完成一些操作&#xff1a; I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从…

jetty xml解析

1 configure configure为xml的根结点&#xff0c;class指定所配置的对象的类&#xff0c;这个configure会创建一个该类的对象&#xff0c;然后根据该xml对其进行配置。id用来对该对象进行标识&#xff0c;在整个jetty中具有唯一性&#xff0c;相同id的xml configure文件配置的是…

java 歌词_请问吧内有大神用JAVA做过桌面歌词吗

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼写了个简单的例子给你&#xff1a;public class TextChangePane extends JComponent implements ActionListener {private static final int CYCLE_TIME 10000;private long startTime 0;private long nowTime 0;private float …

组播相对于单播和广播的优势

组播协议允许将一台主机发送的数据通过网络路由器和交换机复制到多个加入此组组播协议。 与现在广泛使用的单播协议的不同之处在于&#xff0c;一个主机用单播协议向n个主机发送相同的数据时&#xff0c;发送主机需要分别向n个主机发送&#xff0c;共发送n次。一个主机用组播协…

安装nginx及fastdfs-nginx-module

1.先了解背景&#xff1a; FastDFS为什么要结合Nginx以及FastDFS原理&#xff0c;请参考文章&#xff1a; FastDFS为什么要结合Nginx以及FastDFS原理 2.准备工作&#xff1a; 安装安装Nginx所需的环境&#xff0c;参考文献&#xff1a;Ubuntu 18.04.1安装Nginx apt install …

如何让自己的内心强大起来

内心强大的人是指一个人的精神境界达到了一定的级别&#xff01;以至于让人们折服&#xff01; 世界上有这么一种人&#xff0c;似乎特别得到老天爷的偏爱——他总是有自己的理想&#xff0c;并且总是努力去做&#xff0c;最重要的是&#xff0c;老天爷每一次都会帮他取得成功…

什么是软件工程

软件工程是指导计算机软件开发和维护的一门工程学科。采用工程的概念、原理、技术和方法来开发与维护软件&#xff0c;把经过时间考验而证明正确的管理技术和当前能够得到的最好的技术方法结合起来&#xff0c;以经济地开发出高质量的软件并有效地维护它&#xff0c;这就是软件…

linux下的静态库与动态库

目录 静态库定义&#xff1a;生成及使用方法&#xff1a;静态库的优缺点动态库定义&#xff1a;生成及使用方法&#xff1a;动态库优缺点&#xff1a;静态库 先说说我们为什么需要库&#xff1f; 当有些代码我们大量会在程序中使用比如&#xff08;scanf&#xff0c;printf等&a…

esrgan_ESRGAN: Enhanced Super-Resolution Generative Adversarial Networks【阅读笔记】

针对SRGAN提出的几点改进&#xff0c;获得了PIRM2018视觉质量的第一名。首先是使用去掉BN层的Residual in Residual Dense Block作为网络的basic unit。并且使用residual scling 和 smaller initialization帮助训练更深的网络。第二点改进是使用了Relativistic Discriminator来…

PostgreSQL Frontend/Backend protocol (通信协议)

标签 PostgreSQL , protocol , proxy , 通信协议 背景 理解PostgreSQL的通信协议可以更好的开发类似SQL代理&#xff0c;SQL中间件&#xff0c;SQL防火墙&#xff0c;连接池等软件。 学习资料与软件 《PostgreSQL 读写分离代理 - Crunchy Proxy(base on golang)》 Postgres on …