Guava源码分析——ServiceManager
ServiceManager类:
.jpg)
NEW
|
服务在这个状态下是不活跃的,它的作用和消耗的资源都非常小
|
STARTING
|
服务在这个状态过渡到RUNNING
|
RUNNING
|
服务在这个状态下运作
|
STOPPING
|
服务在这个状态过渡到RUNNING
|
TERMINATED
|
服务在这个状态下,说明已正常执行
|
FAILED
|
服务遇到问题,已无法启动或终止
|
void awaitStopped()等待所有服务都到达终止状态(所有服务的状态应该为TERMINATED或FAILED)
如果所有服务的状态为RUNNING,则返回true
获取所有服务的当前状态的快照
返回完成启动的服务的加载时间
.jpg)
启动所有服务:
public ServiceManager startAsync() {
//验证所有服务的初始状态是否为NEW。
for (Map.Entry<Service, ServiceListener> entry : services.entrySet()) {
Service service = entry.getKey();
State state = service.state();
checkState(state == State.NEW, "Service %s is %s, cannot start it.", service,
state);
}
//执行所有服务的start方法。
for (ServiceListener service : services.values()) {
service.start();
}
return this;
}
终止所有服务:
public ServiceManager stopAsync() {
for (Service service : services.keySet()) {
service.stop();
}
return this;
}
在重写start方法时,可以做一些初始化工作,返回结果为ListenableFuture<State>,调用其get方法时,将在该服务启动后,获得其状态变量(RUNNING,STOPPING或TERMINATED),如果服务启动失败,get方法将抛出ExecutionException异常,同时服务状态将为FAILED。
在重写stop方法时,返回结果也为ListenableFuture<State>,调用其get方法时,将在该服务结束后,获得其状态变量TERMINATED或抛出ExecutionException异常。
|
void serviceFinishedStarting(Service service, boolean currentlyHealthy)
|
在服务完成启动时调用
|
void serviceTerminated(Service service)
|
在服务TERMINATED时调用
|
void serviceFailed(final Service service)
|
在服务FAILED时调用
|
void serviceStopped(Service service)
|
在服务TERMINATED或FAILED时调用
|
void executeListeners()
|
执行queuedListeners中所有的监听器
|
void addListener(Listener listener, Executor executor)
|
同上
|
void awaitHealthy()
|
同上
|
boolean awaitHealthy(long timeout, TimeUnit unit)
|
同上
|
void awaitStopped()
|
同上
|
boolean awaitStopped(long timeout, TimeUnit unit)
|
同上
|
.jpg)
public void awaitHealthy() {
state.awaitHealthy();
checkState(isHealthy(), "Expected to be healthy after starting");
}
|
private void waitUninterruptibly(Guard guard, boolean signalBeforeWaiting) {
//所有服务都已启动 或 部分服务已终止,则直接返回,无需等待;
if (!guard.isSatisfied()) {
if (signalBeforeWaiting) {
signalConditionsOfSatisfiedGuards(null);
}
incrementWaiters(guard);
try {
final Condition condition = guard.condition;
do {
condition.awaitUninterruptibly();
} while (!guard.isSatisfied());//若存在未启动的服务,且没有全部终止,则继续等待;
} finally {
decrementWaiters(guard);
}
}
}
|
for (final ListenerExecutorPair pair : listeners) {
queuedListeners.add(new Runnable() {
@Override public void run() {
pair.execute(new Runnable() {
@Override public void run() {
pair.listener.stopped();
}
});
}
});
}
|
封装了另一种服务及其启动时间,同时会根据当前状态调用ServiceManagerState的serviceFinishedStarting ,serviceTerminated ,serviceFailed 方法。
ServiceListener listener = new ServiceListener(service, state);
service. addListener(listener, executor); |
@Override
public void addListener(Listener listener, Executor executor) {
this.listener =
listener;
System.out.println(serviceInfo+"注册监听器");
}
|
@Override
public ListenableFuture<State> stop() {
listener. terminated(state);
System.out.println(serviceInfo + "终止...");
return null;
}
|
@Override public void terminated(State from) {
logger.info("Service " + service + " has terminated. Previous state was " + from + " state.");
state.monitor.enter();
try {
if (from == State.NEW) {
startTimer();
finishedStarting(false);
}
state.serviceTerminated(service);
} finally {
state.monitor.leave();
state.executeListeners();
}
}
|
private void serviceStopped(Service service) {
checkState(unstoppedServices > 0, "All services should have already stopped but %s just stopped.", service);
unstoppedServices--;
if (unstoppedServices == 0) {
checkState(unstartedServices == 0, "All services are stopped but %d services haven't finished starting", unstartedServices);
for (final
ListenerExecutorPair pair : listeners) {
queuedListeners.add(new Runnable() {
@Override public void run() {
pair.execute(new Runnable() {
@Override public void run() {
pair.listener.stopped();
}
});
}
});
}
listeners.clear();
}
}
|
这些监听器除了有stopped方法,还有healthy及failure方法,通过这几个方法,我们可以监视所有服务的运行状态,在下面的例子中,我们可以看到运行结果中出现"服务运行结束!"字样,说明已检测到所有服务都运行结束。
public class ServiceImp implements Service {
private State state = NEW;
private String serviceInfo;
private Listener listener;
ServiceImp(int num){
this.serviceInfo = "第"+num+"个任务:";
}
@Override
public ListenableFuture<State> start() {
System.out.println(serviceInfo+"启动...");
listener.starting();
return null;
}
@Override
public State startAndWait() {
return state;
}
@Override
public boolean isRunning() {
if(state== RUNNING)
return true;
else
return false;
}
@Override
public State state() {
return state;
}
@Override
public ListenableFuture<State> stop() {
listener.
terminated(state);
System.out.println(serviceInfo + "终止...");
return null;
}
@Override
public State stopAndWait() {
return state;
}
@Override
public Throwable failureCause() {
return null;
}
@Override
public void addListener(Listener listener, Executor executor) {
this.listener =
listener;
System.out.println(serviceInfo+"注册监听器");
}
}
|
public class Server {
public static void main(String[] args) {
List<Service> services = Lists.newArrayList();
for (int num = 0; num < 5; num++) {
ServiceImp serviceImp = new ServiceImp(num);
services.add(serviceImp);
}
System.out.println("*******构造服务管理器*******");
final ServiceManager serviceManager = new ServiceManager(services);
serviceManager.
addListener(new ServiceManager.Listener() {
@Override
public void healthy() {
System.out.println("服务运行健康!");
}
@Override
public void stopped() {
System.out.println("服务运行结束!");
}
@Override
public void failure(Service service) {
System.out.println("服务运行失败!");
}
}, MoreExecutors.sameThreadExecutor());
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
System.out.println("********终止所有任务********");
serviceManager.stopAsync().awaitStopped(10, TimeUnit.SECONDS);
} catch (Exception timeout) {
System.out.println("timeout");
}
}
});
System.out.println("********启动所有任务********");
serviceManager.startAsync();
}
}
|
*******构造服务管理器*******
第0个任务:注册监听器
第1个任务:注册监听器
第2个任务:注册监听器
第3个任务:注册监听器
第4个任务:注册监听器
********启动所有任务********
第0个任务:启动...
第1个任务:启动...
第2个任务:启动...
第3个任务:启动...
第4个任务:启动...
********终止所有任务********
第0个任务:终止...
第1个任务:终止...
第2个任务:终止...
第3个任务:终止...
服务运行终止!
第4个任务:终止...
|
Guava源码分析——ServiceManager的更多相关文章
- Guava 源码分析(Cache 原理 对象引用、事件回调)
前言 在上文「Guava 源码分析(Cache 原理)」中分析了 Guava Cache 的相关原理. 文末提到了回收机制.移除时间通知等内容,许多朋友也挺感兴趣,这次就这两个内容再来分析分析. 在开 ...
- Guava 源码分析之Cache的实现原理
Guava 源码分析之Cache的实现原理 前言 Google 出的 Guava 是 Java 核心增强的库,应用非常广泛. 我平时用的也挺频繁,这次就借助日常使用的 Cache 组件来看看 Goog ...
- [Guava源码分析]ImmutableCollection:不可变集合
摘要: 我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3888557.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的 ...
- [Guava源码分析]Ordering:排序
我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3876466.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...
- Guava 源码分析(Cache 原理)
前言 Google 出的 Guava 是 Java 核心增强的库,应用非常广泛. 我平时用的也挺频繁,这次就借助日常使用的 Cache 组件来看看 Google 大牛们是如何设计的. 缓存 本次主要讨 ...
- Guava 源码分析之 Beta, GwtCompatible, GwtIncompatible, Charset, HashCode
com.google.common.annotations.Beta /** * 表明一个公用API的未来版本是受不兼容变更或删除限制的 * 拥有这个注释标志的API不受任何兼容性保证 * */ @R ...
- [Guava源码分析]Objects 和 ComparisonChain:帮助重写Object方法
我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3874194.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...
- [Guava源码分析] Preconditions 前置条件
我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3874170.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...
- Guava cacha 机制及源码分析
1.ehcahce 什么时候用比较好:2.问题:当有个消息的key不在guava里面的话,如果大量的消息过来,会同时请求数据库吗?还是只有一个请求数据库,其他的等待第一个把数据从DB加载到Guava中 ...
随机推荐
- [Redux] Extracting Presentational Components -- AddTodo
The code to be refactored: let nextTodoId = 0; class TodoApp extends Component { render() { const { ...
- 使用区域组织 ASP.NET MVC 应用程序
MVC 模式可将应用程序的模型(数据)逻辑与其呈现逻辑和业务逻辑分离. 在 ASP.NET MVC 中,这种逻辑分离还在项目结构中以物理方式实现,在该项目结构中,控制器和视图保存在使用命名约定定义关系 ...
- (转).net程序员转战android第一篇---环境部署
原文,整个序列一样http://www.cnblogs.com/Twmin/p/3148892.html 对于.net开发人员去写java,可谓说是见山是山, 因为太多的相同; 最近段时间因工作因素, ...
- javascript实现倒计时程序
最近在网上看到一道这样的面试题: 题: 网页中实现一个计算当年还剩多少时间的倒数计时程序,要求网页上实时动态显示“××年还剩××天××时××分××秒”? 我实现了,发现挺有意思,下面把我的代码贴出来 ...
- 关于sql2005 与 myeclipse进行连接出现的小问题
C盘目录下没有jdbc这个文件夹,所以从网上下一个 这个是2008连接jdbc用的 正常解压第一个到相应的目录 主要是注意一个叫tcp/ip的协议,米有找到64位的 点击这里的tcp ip就哦了但是他 ...
- gitweb随记
1.安装gitweb,命令安装即可 apt-get install gitweb 2.clone cgi $ git clone git://git.kernel.org/pub/scm/git/gi ...
- WordPress插件制作教程(八): 最后总结
WordPress插件教程最后一篇,还是为大家简单的做下总结.这次插件制作教程讲的内容和知识点个人觉得不是很多,因为插件制作不单单是这些内容,它涉及的知识很多很多,不是说你会一些函数就可以做出一个好的 ...
- DESTOON伪静态的设置/news/1.html格式
在本地测试了,DT默认伪静态格式是这样http://127.0.0.2/news/show/1.htmlhttp://127.0.0.2/news/show1-1.html但是这种不利于seo优化所以 ...
- c# 弹出框-后台调前台函数
前台代码: <script src="../../../Common/Scripts/Order/popup.js" type="text/javascript&q ...
- Bootstrap 模态对话框 remote指定内容加载
第一个页面: .....其他内容..... <div class="modal" id="ID_ReformDetail"> <div cla ...