• Guava的Service


    Guava的Service

    一、Guava的Service介绍

    Guava的Service接口代表一个对象拥有操作状态,带有从开始到结束的方法。例如,web服务、RPC服务、计时器等能够实现Service接口。管理此类服务的状态,它们需要恰当的启动和停止管理,它们很重要,尤其是设计多线程调度。Guava 提供了一些骨架来为您管理状态逻辑和同步细节。

    二、使用Service

    一个正常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 接口是微妙的、复杂的。我们不推荐直接实现它。相反请使用抽象的基础类作为它的实现。每个基础类都支持特定的线程模型。

    三、实现

    3.1 AbstractIdleService

    那个AbstractIdleService骨架实现了Service。在“running”状态下不需要做任何事情。因此,在运行的不需要线程——除了执行启动和关闭操作。实现这样的服务就像扩展 AbstractIdleService 并实现 startUp() 和 shutDown() 方法一样简单。

    3.2 AbstractExecutionThreadService

    一个 AbstractExecutionThreadService 执行启动、运行、停止行为在单个线程中。你必须覆盖run()方法。它必须响应停止请求。

    覆盖 startUp() 和 shutDown() 是可选的,但将为您管理服务状态。

    请注意,start() 调用您的 startUp() 方法,为您创建一个线程,并在该线程中调用 run()。 stop() 调用 triggerShutdown() 并等待线程终止。

    3.3 AbstractScheduledService

    一个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

    3.4 AbstractService

    当你需要做自己的手动线程管理的时候,直接覆盖AbstractService

    为了实现AbstractService,你必须实现两个方法:

    • doStart() 由第一次调用 startAsync() 直接调用,您的 doStart() 方法应执行所有初始化,然后在启动成功时最终调用 notifyStarted() 或在启动失败时调用 notifyFailed()。
    • doStop() doStop() 由第一次调用 stopAsync() 直接调用,您的 doStop() 方法应该关闭您的服务,然后如果关闭成功则最终调用 notifyStopped() 或如果关闭失败则调用 notifyFailed()。

    你的doStart()doStop()方法应该是快的。如果你要做代价比较高的初始化,比如读文件、打开网络连接,或任何其它阻塞的操作,你应该考虑将它们移到另外的线程。

    四、使用ServiceManager

    除了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保证按启动时间排序。
  • 相关阅读:
    Vue3初始化写法
    ✨Linux定时备份mysql中的数据库(包括Docker)
    TeeChart 的使用从入门到精通
    通达信软件L2接口的委托队列有什么用?
    工厂方法演进
    33.Mybatis-Plus
    【21】c++设计模式——>装饰模式
    深入理解Linux内核页表映射分页机制原理
    Nginx安装、配置
    【ELK使用指南 2】常用的 Logstash filter 插件详解(附应用实例)
  • 原文地址:https://blog.csdn.net/hefrankeleyn/article/details/126088345