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;如正…

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…

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来…

启动FastDFS服务,使用python客户端对接fastdfs完成上传测试

1.启动tracker、storage、nginx服务&#xff1a; 启动fdfs_trackerd&#xff1a;sudo service fdfs_trackerd start 启动fdfs_storaged &#xff1a;sudo service fdfs_storaged start 启动Nginx&#xff1a;sudo /usr/local/nginx/sbin/nginx 注&#xff1a;此处给出重启服务…

Python学习-终端字体高亮显示

1、采用原生转义字符序列&#xff0c;对Windows有的版本不支持&#xff08;比如win7&#xff09;&#xff0c;完美支持Linux 实现过程&#xff1a; 终端的字符颜色是用转义序列控制的&#xff0c;是文本模式下的系统显示功能&#xff0c;和具体的语言无关。 转义序列是以ESC开头…

js下载文件 java_[Java教程]使用js实现点击按钮下载文件

[Java教程]使用js实现点击按钮下载文件0 2016-11-11 19:02:54有时候我们在网页上需要增加一个下载按钮&#xff0c;让用户能够点击后下载页面上的资料&#xff0c;那么怎样才能实现功能呢&#xff1f;这里有两种方法&#xff1a;现在需要在页面上添加一个下载按钮&#xff0c;点…

Django二次开发对接FastDFS

1.自定义文件存储器类 配置文件settings中加入如下配置 # 设置Django的文件存储类、&#xff08;名字固定&#xff09; DEFAULT_FILE_STORAGEutils.fdfs.storage.FDFSStorage# 设置fdfs使用的client.conf文件路径&#xff08;名字自己定义&#xff09; FDFS_CLIENT_CONF./util…

微信支付 java 集成案例_Spring Boot项目中集成微信支付v3

1. 前言最近忙的一批&#xff0c;难得今天有喘气的机会就赶紧把最近在开发中的一些成果分享出来。前几日分享了自己写的一个微信支付V3的开发包payment-spring-boot-starter&#xff0c;就忙里偷闲完善了一波。期间给微信支付提交了6个BUG&#xff0c;跟微信支付的产品沟通了好…

16. vim

vim编辑器是vi的升级版本&#xff0c;带颜色显示安装yum install -y vim-enhanced将passwd文件复制到其他目录下&#xff0c;vim后没有颜色 一般模式上下左右方向键或kjhl四个键移动光标n方向键 向特定方向移动n位ctrl b 或 pageup 向上翻页ctrl f 或 pagedown 向下翻页0或sh…

Jmeter(三)_配置元件

HTTP Cookie Manager 用来存储浏览器产生的用户信息 Clear Cookies each Iteration&#xff1a;每次迭代请求&#xff0c;清空cookies&#xff0c;GUI中定义的任何cookie都不会被清除。Implementation&#xff1a;默认HC4CookieHandlerCookie Policy&#xff1a;将用于管理Cook…

Django项目--首页静态化

0前言 1.使用Celery生成静态页面 task.py中新增任务函数generate_static_index_html()&#xff0c;任务函数生成静态页面。 app.task def generate_static_index_html():产生首页静态页面# 获取商品的种类信息types GoodsType.objects.all()# 获取首页轮播商品信息goods_bann…

C语言指针,申请、释放内存,线程

2019独角兽企业重金招聘Python工程师标准>>> 1&#xff1a;普通情况下&#xff0c;C语言的指针是使用虚拟地址&#xff0c;并非物理地址&#xff1b; 2&#xff1a;C语言mallco函数可以根据输入的值&#xff0c;申请一块连续的内存&#xff1b;free&#xff08;*p&a…

Docker在Ubuntu16.04上安装

转自&#xff1a;http://blog.51cto.com/collen7788/2047800 1、添加Docker源 sudo apt-get update 2、增加CA证书 sudo apt-get install apt-transport-https ca-certificates 3、添加GPG Key(一种加密手段) sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:…

Django项目--静态首页的数据缓存(设置、获取、更新)

0 前言 将处理计算的结果先临时保存起来&#xff0c;下次使用的时候可以先直接使用&#xff0c;如果没有这个备份的数据&#xff0c;重新进行计算处理。 将缓存数据保存在内存中 &#xff08;本项目中保存在redis中&#xff09; cache注意事项&#xff1a; 1&#xff09;如果…

关于腾讯算法大赛

腾讯算法大赛 本文参考于我协会前会长吴师兄的文档 腾讯社交广告高校算法大赛是面向高校大学生的算法大赛&#xff0c;作为腾讯核心的广告业务单元&#xff0c;腾讯社交广告通过对海量社交数据进行深入分析&#xff0c;构建多样广告场景&#xff0c;与8亿用户连接对话。在大数据…

NavigationView更改菜单icon和title颜色变化效果

NavigationView menu默认icon和title会随着菜单状态改变而改变&#xff0c;选择某个菜单后再次打开侧边菜单后会发现该菜单的icon和title会变成应用的主颜色&#xff0c;其他菜单项仍然为黑色。 如果想关闭系统默认的这个效果&#xff0c;有两种方式&#xff1a; 1. XML布局文件…

kangle服务器搭建java_linux下kangle虚拟主机-架设java空间的教程及心得

1. chmod x jdk-6u31-linux-i586-rpm.bin2. ./jdk-6u31-linux-i586-rpm.bin复制代码(注&#xff1a;如果下载的版本不同输入实际版本)2.下载插件包:1. wget http://www.kanglesoft.com/download/ent/easypanel-tomcat-lin-1.0.tar.gz2. tar xzf easypanel-tomcat-lin-1.0.tar.g…