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)
|
同上
|
|
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中 ...
随机推荐
- TBB入门
获取TBB TBB的官方网站在http://threadingbuildingblocks.org/,可以在它的Downloads页面里找到Commercial Aligned Release,最新版 ...
- ARM指令集——数据处理指令
ARM汇编指令集 ARM汇编文件的组成 指令:编译完成后作为一条指令(机器码)存储在内存单元中,CPU执行时能够完成处理的操作 伪指令:在编译时替换成能被识别的ARM指令 伪操作:知道编译器进行编译, ...
- Hacker(23)----破解常见文件密码
Win7中,office文档.压缩文件等都是常见的文件,这些文档含有重要的信息,即使用户为这些文件设置了密码,黑客也会有办法破解. 一.破解office文档密码 破解office文档密码常用工具是Ad ...
- Some good iOS questions
这里,我列举了一些在Stackoverflow中一些比较好的关于iOS的问题.大部分我列举的问题都是关于Objective C.所有问题中,我比较喜欢“为什么”这一类型的问题. 问题 1. What’ ...
- eclipse 404以及tomcat failed to start错误
eclipse中的servlet项目有时会不编译,不编译可能就会出现404错误,因为在build path的输出目录并没有class文件,然而如果在输出目录引入之前编译的class文件,就可能出现cl ...
- Eclipse下绿色安装插件Aptana、Swing
本文主要针对Ecplise下绿色安装插件,写本篇博客也是因为笔者在Ecplise下安装Aptana时不断安装出现错误,所以写下自己安装成功以及之前出错的原因,也搜集了许多资料在此一并总结一下吧! Ec ...
- IEquatable(T) interface in .Net
原文:http://weblogs.asp.net/pawanmishra/iequatable-t-interface-in-net 泛型方法: public static bool AreEqua ...
- .net安装windows服务配置文件config
.net安装windows服务 : 在windows服务的项目(WindowsService1)代码文件中有一个app.config 配置文件,可以通过此文件进行时间等的更改而无需重新生成项目:那我们 ...
- Jlink仿真器下载程序时出现Invalid ROM table!
原因:仿真器时钟设置不对,应该将时间改低一点.
- django解决跨域请求的问题
跨域请求可以用jsonp来解决,不过今天我发现一个很好用的包:django-cors-headers 只需要简单地配置一下就可 被请求方的setting.py中的配置如下: INSTALLED_APP ...