Guava的Service接口代表一个对象拥有操作状态,带有从开始到结束的方法。例如,web服务、RPC服务、计时器等能够实现Service接口。管理此类服务的状态,它们需要恰当的启动和停止管理,它们很重要,尤其是设计多线程调度。Guava 提供了一些骨架来为您管理状态逻辑和同步细节。
一个正常Service的生命周期:
Service.State.NEW
到Service.State.STARTING
到Service.State.RUNNING
到Service.State.STOPPING
到Service.State.TERMINATED
一个已经停止的服务不能重新运行。如果服务在启动(starting)、运行(running)或停止(stopping)的时候失败,它将进入Service.State.FAILED
状态。
如果NEW
状态的服务,可以通过startAsync()
以异步的方式启动。因此,您应该构建您的应用程序,使其具有启动每个服务的唯一位置。
停止服务是类似的,使用异步的stopAsync()
方法。但与startAsync()
方法不同,可以安全的调用该方法多次。这是为了处理关闭服务会发生的竞争。
Serevice也提供了一些方法等待服务的转换完成:
addListener()
。它允许你添加Service.Listener
,它将会在每次状态转换的时候进行调用。注: 如果在添加侦听器时服务不是 NEW,则任何已经发生的状态转换都不会在侦听器上重播。awaitRunning()
。这是不间断的,不抛出任何检查异常,并在服务完成启动后返回。如果服务无法启动,则会引发 IllegalStateException。类似的,awaitTerminated()
等待服务达到终止状态(TERMINATED或FAILED)。这两种方法还具有允许指定超时的重载。Service 接口是微妙的、复杂的。我们不推荐直接实现它。相反请使用抽象的基础类作为它的实现。每个基础类都支持特定的线程模型。
那个AbstractIdleService骨架实现了Service。在“running”状态下不需要做任何事情。因此,在运行的不需要线程——除了执行启动和关闭操作。实现这样的服务就像扩展 AbstractIdleService 并实现 startUp() 和 shutDown() 方法一样简单。
一个 AbstractExecutionThreadService 执行启动、运行、停止行为在单个线程中。你必须覆盖run()
方法。它必须响应停止请求。
覆盖 startUp() 和 shutDown() 是可选的,但将为您管理服务状态。
请注意,start() 调用您的 startUp() 方法,为您创建一个线程,并在该线程中调用 run()。 stop() 调用 triggerShutdown() 并等待线程终止。
一个AbstractScheduledService做一些周期性的任务。子类实现runOneIteration()
指定任务的一次迭代,以及熟悉的startUp()
和shutDown()
方法。
为了描述执行调度,必须实现scheduler()
方法。通常你将使用由AbstractScheduledService.Scheduler
提供的定时。即可以AbstractScheduledService.Scheduler.newFixedDelaySchedule(Duration initialDelay, Duration delay)
,也可以AbstractScheduledService.Scheduler.newFixedRateSchedule(Duration initialDelay, Duration delay)
。和ScheduledExecutorService
中熟悉的方法对应。
自定义Schedule可以通过实现AbstractScheduledService.CustomScheduler
。
当你需要做自己的手动线程管理的时候,直接覆盖AbstractService
。
为了实现AbstractService,你必须实现两个方法:
doStart()
由第一次调用 startAsync() 直接调用,您的 doStart() 方法应执行所有初始化,然后在启动成功时最终调用 notifyStarted() 或在启动失败时调用 notifyFailed()。doStop()
doStop() 由第一次调用 stopAsync() 直接调用,您的 doStop() 方法应该关闭您的服务,然后如果关闭成功则最终调用 notifyStopped() 或如果关闭失败则调用 notifyFailed()。你的doStart()
和doStop()
方法应该是快的。如果你要做代价比较高的初始化,比如读文件、打开网络连接,或任何其它阻塞的操作,你应该考虑将它们移到另外的线程。
除了Service
骨架的实现,Guava提供了ServiceManager
类,使操作涉及多个Service实现更容易。创建一个带有一个集合Service的ServiceManager
。然后能管理它们:
startAsync()
将启动管理下的所有服务。非常像Service#startAsync()
,你只需要调用一次,所有的service都NEW。stopAsync()
停止管理下的所有服务。addListener
添加ServiceManager.Listener
,当主要的状态转换的时候,监听将会调用;awaitHealthy()
将等待所有的service到达RUNNING
状态awaitStopped()
将等待所有的service到达终止状态或者检查它们:
isHealthy()
如果所有的service是RUNNING状态;servicesByState()
返回按状态索引的所有服务的一致快照。startupTimes()
从受管理的服务返回一个映射到该服务启动所需的时间(以毫秒为单位)。 返回的Map保证按启动时间排序。