ServiceManager类:

     用于监控服务集的管理器,该类提供了诸如startAsync、stopAsync、servicesByState方法来运行、结束和检查服务集,而且,通过监听器机制还能监控状态的改变。
     建议通过此类来管理服务的生命周期,状态转变则通过其它机制来执行。例如,如果服务集通过除startAsync之外的某些机制启动,那么监听器将在合适的时候被唤醒,同时awaitHealthy 也仍将按预期工作。
      
 
 
服务生命周期State
NEW
服务在这个状态下是不活跃的,它的作用和消耗的资源都非常小
STARTING
服务在这个状态过渡到RUNNING
RUNNING
服务在这个状态下运作
STOPPING
服务在这个状态过渡到RUNNING
TERMINATED
服务在这个状态下,说明已正常执行
FAILED
服务遇到问题,已无法启动或终止
 
 
ServiceManager主要方法
void addListener(Listener listener, Executor executor)
在executor上注册一个监听器
ServiceManager startAsync()
启动所有被管理的服务,只有当所有服务的状态为NEW时,调用此方法才不会抛异常
void awaitHealthy()
等待服务管理器变得healthy(所有服务的状态都为RUNNING )
void awaitHealthy(long timeout, TimeUnit unit)
在一定时间内,等待服务管理器变得healthy(所有服务的状态都为RUNNING )
ServiceManager stopAsync()
stop()所有管理的服务

void awaitStopped()等待所有服务都到达终止状态(所有服务的状态应该为TERMINATED或FAILED)

void awaitStopped(long timeout, TimeUnit unit)
在一定时间内,等待所有服务都到达终止状态
boolean isHealthy()

如果所有服务的状态为RUNNING,则返回true

ImmutableMultimap<State, Service> servicesByState()

获取所有服务的当前状态的快照

ImmutableMap<Service, Long> startupTimes()

返回完成启动的服务的加载时间

 
 
ServiceManager的构建——
    1)创建一个ServiceManagerState;
    2)创建一个Executor ;
    3)根据每一个Service及ServiceManagerState创建相应的ServiceListener;
    4)将每一个ServiceListener注册到Executor 上,此时会调用到每个Service的addListener方法;
    5)为services 添加Service与ServiceListener的键值对。
 
几个主要函数:
  启动所有服务:

  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异常。

 

 
 
ServiceManagerState类——ServiceManager的所有可变状态的封装体。
 
         
ServiceManagerState主要方法
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)
同上
 
ServiceManager中的方式实际调用的即为以上方法。
 
 主要成员变量:
1)记录了服务总数(numberOfServices),未启动服务数(unstartedServices)及未终止服务数(unstoppedServices),初始值都为服务总数。
这些状态的作用体现在两个地方:
① 等待所有服务处于健康状态,涉及的条件awaitHealthGuard为:所有服务都已经启动 或 部分服务已终止。
            该条件应用在,等待所有服务处于健康状态的主体函数中:
     
    public void awaitHealthy() {

                    state.awaitHealthy();
                    checkState(isHealthy(), "Expected to be healthy after starting");
              }

        主要分两部分:
        首先在state.awaitHealthy()中,通过下面函数,等待所有服务都启动
        
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);
                  }
            }
      }

              接着通过isHealthy()函数,判断所有服务处在RUNNING状态。


 ② 判断所有服务是否处于终止状态,需要满足的条件stoppedGuard即为:未终止服务数等于0。

2)Queue<Runnable> queuedListeners队列保存等待执行的监听器,调用executeListeners()时,会依次将队列中的所有方法执行并移除。

 
3)List<ListenerExecutorPair> listeners 保存了在状态转变时,需要通知的监听器,应用:
            ① serviceStopped方法被调用时,unstoppedServices减一,添加listeners中的所有监听器的stopped方法至queuedListeners队列。
            ② serviceTerminated方法被调用时,实际调用serviceStopped方法。
            ③ serviceFailed方法被调用时,添加listeners中的所有监听器的failure方法至queuedListeners队列,并调用serviceStopped方法。
            ④ serviceFinishedStarting方法被调用时,unstartedServices减1,如果参数currentlyHealthy为真,且所有服务都已启动且没终止,添加listeners中的所有监听器的 healthy方法至queuedListeners队列。
添加方法都如下:
     
  
for (final ListenerExecutorPair pair : listeners) {

          queuedListeners.add(new Runnable() {
            @Override public void run() {
              pair.execute(new Runnable() {
                @Override public void run() {
                  pair.listener.stopped();
                }
              });
            }
          });
        }

  
 
ServiceListener类:

封装了另一种服务及其启动时间,同时会根据当前状态调用ServiceManagerState的serviceFinishedStarting ,serviceTerminated ,serviceFailed 方法。

 
 

DEMO:
下面从终止服务为例,说下Service及ServiceManager的监听器,也不知道自己这样用对不对....
我们可以在实现Service接口的类中,重写addListener方法,该方法将在构造服务管理器时,被调用:
调用处:

ServiceListener listener = new ServiceListener(service, state);
       service.
addListener(listener, executor);

 
重写的addListener方法:
    @Override
      public void addListener(Listener listener, Executor executor) {
           this.listener =
 
listener;
           System.out.println(serviceInfo+"注册监听器");
      }

 
接着重写stop方法,当服务管理器执行stopAsync() 方法时,将依次执行每个服务的stop方法:
    @Override
    public ListenableFuture<State> stop() {
       
 
listener.
terminated(state);
        System.out.println(serviceInfo + "终止...");
        return null;
    }

 
此处我们调用listener的terminated方法:
    
@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();
          }
    }

 
serviceTerminated方法实际调用的为serviceStopped方法,在该方法中将unstoppedServices(未终止服务数)减一,若所有服务都已终止,则将listeners中所有监听器的stopped方法加入queuedListeners队列中稍后执行。
    
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();
          }
    }

 

listeners中的监听器,是通过服务管理器的addListener方法(Service也有addListener方法)添加的,在该方法中会将监听器添加到listeners队列中,当服务状态发生改变时,通知队列中的监听器。

这些监听器除了有stopped方法,还有healthy及failure方法,通过这几个方法,我们可以监视所有服务的运行状态,在下面的例子中,我们可以看到运行结果中出现"服务运行结束!"字样,说明已检测到所有服务都运行结束。

 

ServiceImp实现类:
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的更多相关文章

  1. Guava 源码分析(Cache 原理 对象引用、事件回调)

    前言 在上文「Guava 源码分析(Cache 原理)」中分析了 Guava Cache 的相关原理. 文末提到了回收机制.移除时间通知等内容,许多朋友也挺感兴趣,这次就这两个内容再来分析分析. 在开 ...

  2. Guava 源码分析之Cache的实现原理

    Guava 源码分析之Cache的实现原理 前言 Google 出的 Guava 是 Java 核心增强的库,应用非常广泛. 我平时用的也挺频繁,这次就借助日常使用的 Cache 组件来看看 Goog ...

  3. [Guava源码分析]ImmutableCollection:不可变集合

    摘要: 我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3888557.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的 ...

  4. [Guava源码分析]Ordering:排序

    我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3876466.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...

  5. Guava 源码分析(Cache 原理)

    前言 Google 出的 Guava 是 Java 核心增强的库,应用非常广泛. 我平时用的也挺频繁,这次就借助日常使用的 Cache 组件来看看 Google 大牛们是如何设计的. 缓存 本次主要讨 ...

  6. Guava 源码分析之 Beta, GwtCompatible, GwtIncompatible, Charset, HashCode

    com.google.common.annotations.Beta /** * 表明一个公用API的未来版本是受不兼容变更或删除限制的 * 拥有这个注释标志的API不受任何兼容性保证 * */ @R ...

  7. [Guava源码分析]Objects 和 ComparisonChain:帮助重写Object方法

    我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3874194.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...

  8. [Guava源码分析] Preconditions 前置条件

    我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3874170.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...

  9. Guava cacha 机制及源码分析

    1.ehcahce 什么时候用比较好:2.问题:当有个消息的key不在guava里面的话,如果大量的消息过来,会同时请求数据库吗?还是只有一个请求数据库,其他的等待第一个把数据从DB加载到Guava中 ...

随机推荐

  1. 为iPhone6设计自适应布局(二)

    Size Classes 自适应布局的布局约束自然是好东西,但也不是万能的,有时候我们也需要使用最基本的布局,所以使用size classes将它们两者结合起来才能碰撞出更有激情的火花. 引用我上篇译 ...

  2. android EditText插入字符串到光标所在位置

    EditText mTextInput=(EditText)findViewById(R.id.input);//EditText对象 int index = mTextInput.getSelect ...

  3. JavaScript获取元素样式

    原生的JavaScript获取写在标签内部的样式很简单: <div class="test" id="test" style="width:10 ...

  4. css布局详解(一)——盒模型

    一.网页布局的几种情况 今天让我们总结一下在css布局的各种情况做一个总结,为我们以后布局网页时做一个参考. 先看一张图,这是去年cssConf大会时阿里的 @寒冬winter 老师放出来的: 如图所 ...

  5. C# XML 根级别上的数据无效

    XmlDocument加载xml方法 XmlDocument doc = new XmlDocument(); //加载xml 字符串 doc.LoadXml(_Store); //加载xml文件 d ...

  6. return 与 finally

    (function hello() { try { return console.log('return'); } catch (e) { } finally { console.log('final ...

  7. canvas-js贝塞尔曲代码在线生成工具

    canvas贝塞尔曲代码在线生成工具 可以快速生成二次.三次贝塞尔曲线的源码生成器,方便经常使用到canvas画图的同学使用,可以直接预览效果随意画出自己想要的图像. 生成源码效果预览: canvas ...

  8. 逃离迷宫(HDU 1728 BFS)

    逃离迷宫 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  9. [bzoj 1001][Beijing2006]狼抓兔子 (最小割+对偶图+最短路)

    Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一 ...

  10. 使用filter统一设置编码

    1.写一个类EncodingFilter.java,实现javax.servlet.Filter(文件命名做到见名知意) package com.filter; import java.io.IOEx ...