Guava源码分析——ServiceManager
ServiceManager类:
NEW
|
服务在这个状态下是不活跃的,它的作用和消耗的资源都非常小
|
STARTING
|
服务在这个状态过渡到RUNNING
|
RUNNING
|
服务在这个状态下运作
|
STOPPING
|
服务在这个状态过渡到RUNNING
|
TERMINATED
|
服务在这个状态下,说明已正常执行
|
FAILED
|
服务遇到问题,已无法启动或终止
|
void awaitStopped()等待所有服务都到达终止状态(所有服务的状态应该为TERMINATED或FAILED)
如果所有服务的状态为RUNNING,则返回true
获取所有服务的当前状态的快照
返回完成启动的服务的加载时间
启动所有服务:
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)
|
同上
|
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中 ...
随机推荐
- 为iPhone6设计自适应布局(二)
Size Classes 自适应布局的布局约束自然是好东西,但也不是万能的,有时候我们也需要使用最基本的布局,所以使用size classes将它们两者结合起来才能碰撞出更有激情的火花. 引用我上篇译 ...
- android EditText插入字符串到光标所在位置
EditText mTextInput=(EditText)findViewById(R.id.input);//EditText对象 int index = mTextInput.getSelect ...
- JavaScript获取元素样式
原生的JavaScript获取写在标签内部的样式很简单: <div class="test" id="test" style="width:10 ...
- css布局详解(一)——盒模型
一.网页布局的几种情况 今天让我们总结一下在css布局的各种情况做一个总结,为我们以后布局网页时做一个参考. 先看一张图,这是去年cssConf大会时阿里的 @寒冬winter 老师放出来的: 如图所 ...
- C# XML 根级别上的数据无效
XmlDocument加载xml方法 XmlDocument doc = new XmlDocument(); //加载xml 字符串 doc.LoadXml(_Store); //加载xml文件 d ...
- return 与 finally
(function hello() { try { return console.log('return'); } catch (e) { } finally { console.log('final ...
- canvas-js贝塞尔曲代码在线生成工具
canvas贝塞尔曲代码在线生成工具 可以快速生成二次.三次贝塞尔曲线的源码生成器,方便经常使用到canvas画图的同学使用,可以直接预览效果随意画出自己想要的图像. 生成源码效果预览: canvas ...
- 逃离迷宫(HDU 1728 BFS)
逃离迷宫 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- [bzoj 1001][Beijing2006]狼抓兔子 (最小割+对偶图+最短路)
Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一 ...
- 使用filter统一设置编码
1.写一个类EncodingFilter.java,实现javax.servlet.Filter(文件命名做到见名知意) package com.filter; import java.io.IOEx ...