美文网首页工作生活
Google Guava Service(服务)简单介绍

Google Guava Service(服务)简单介绍

作者: tuacy | 来源:发表于2019-06-30 07:54 被阅读0次

       Guava包里的Service框架可以帮助我们把异步操作封装成一个Service服务。让这个服务有了运行状态(我们也可以理解成生命周期),这样我们可以实时了解当前服务的运行状态。同时我们还可以添加监听器来监听服务运行状态之间的变化。

       Guava里面的服务有五种状态,如下所示:

  • Service.State.NEW: 服务创建状态
  • Service.State.STARTING: 服务启动中
  • Service.State.RUNNING:服务启动完成,正在运行中
  • Service.State.STOPPING: 服务停止中
  • Service.State.TERMINATED: 服务停止完成,结束

       所有的服务都需要实现Service接口,里面包括了服务需要实现的一些基本方法,所以我先对Service的方法做一个基本的介绍.

public interface Service {
    /**
     * 启动当前服务
     * 只有当服务的状态是NEW的情况下才可以启动,否则抛出IllegalStateException异常
     */
    @CanIgnoreReturnValue
    Service startAsync();

    /**
     * 判断当前服务是否处在运行状态 (RUNNING)
     */
    boolean isRunning();

    /**
     * 获取当前服务的状态
     */
    Service.State state();


    /**
     * 停止当前服务
     */
    @CanIgnoreReturnValue
    Service stopAsync();

    /**
     * 等待当前服务到达RUNNING状态
     */
    void awaitRunning();

    /**
     * 在指定的时间内等待当前服务到达RUNNING状态
     * 如果在指定时间没有达到则抛出TimeoutException
     */
    void awaitRunning(long timeout, TimeUnit unit) throws TimeoutException;

    /**
     * 等待当期服务到达TERMINATED状态
     */
    void awaitTerminated();

    /**
     * 在指定的时间内等待当前服务达到TERMINATED状态,
     */
    void awaitTerminated(long timeout, TimeUnit unit) throws TimeoutException;

    /**
     * 获取服务器失败的原因
     * 在服务是FAILED的状态的时候调用该函数,否则抛出IllegalStateException异常
     */
    Throwable failureCause();

    /**
     * 监听当前服务的状态改变,
     * executor参数表示,监听回调函数在哪里执行
     */
    void addListener(Service.Listener listener, Executor executor);
}

       那咱们应该怎么来使用Guava里面的Servic.怎么把我们需要实现的异步逻辑包装成服务呢.Guava里面已经给提供了三个基础实现类:AbstractService,AbstractExecutionThreadService,AbstractScheduledService.这里咱们简单的介绍下
AbstractExecutionThreadService和AbstractScheduledService的使用.如果想深入的理解具体的实现逻辑,强烈建议大家去看看这三个类的源码实现逻辑.很有必要,因为你只有充分的了解了这三个类额实现逻辑之后,你才可以根据不同的业务场景自定义自己的服务实现类.

AbstractExecutionThreadService

       AbstractExecutionThreadService可以帮助我们把一个具体的异步操作封装成Service服务。说白了就是把咱们之前在线程的实现逻辑封装成服务.把之前线程的具体实现逻辑搬到AbstractExecutionThreadService的实现方法run()方法去执行。

AbstractExecutionThreadService常用方法介绍

       我们对AbstractExecutionThreadService常用方法做一个简单的解释,首先AbstractExecutionThreadService实现了Service,Service的方法在AbstractExecutionThreadService里面都有,关于这些方法我们就不重复介绍.我们介绍下AbstractExecutionThreadService新加的一些其他的方法。如下所示:

public class AbstractExecutionThreadService {

    ...
    
    /**
     * 开始执行我们服务逻辑的时候会调用,我们可以在里面做一些初始化的操作
     */
    protected void startUp() throws Exception;

    /**
     * 我们当前服务需要执行的具体逻辑
     */
    protected abstract void run() throws Exception;

    /**
     * 服务停止之后会调用的函数,我们可以在里面做 一些释放资源的处理
     */
    protected void shutDown() throws Exception {}

    /**
     * 比如在我们run方法里面有一个无线循环,可以在这个方法里面置状态,退出无线循环,让服务真正停止
     * 调stopAsync函数的时候,会调用该方法
     */
    protected void triggerShutdown() {}
    
    ...
}

       AbstractExecutionThreadService类里面最重要的就是run()方法了,这个方法是我们服务需要具体实现的方法,服务需要处理的具体逻辑在这个方法里面做。

AbstractExecutionThreadService的使用

       我们用一个简单的实例来说明。我们自定义一个AbstractExecutionThreadServiceImpl实现AbstractExecutionThreadService,把我们线程的操作的具体逻辑搬到AbstractExecutionThreadServiceImpl里面去做。

public class AbstractExecutionThreadServiceImpl extends AbstractExecutionThreadService {

    private volatile boolean running = true; //声明一个状态

    @Override
    protected void startUp() {
        //TODO: 做一些初始化操作
    }

    @Override
    public void run() {
        // 具体需要实现的业务逻辑,会在线程中执行
        while (running) {
            try {
                // 等待2s
                Uninterruptibles.sleepUninterruptibly(2, TimeUnit.SECONDS);
                System.out.println("do our work.....");
            } catch (Exception e) {
                //TODO: 处理异常,这里如果抛出异常,会使服务状态变为failed同时导致任务终止。
            }
        }
    }

    @Override
    protected void triggerShutdown() {
        //TODO: 如果我们的run方法中有无限循环啥的,可以在这里置状态,让退出无限循环,,stopAsync()里面会调用到该方法
        running = false; //这里我们改变状态值,run方法中就能够得到响应。=
    }

    @Override
    protected void shutDown() throws Exception {
        //TODO: 可以做一些清理操作,比如关闭连接啥的。shutDown() 是在线程的具体实现里面调用的
    }

}

       针对AbstractExecutionThreadServiceImpl我们写个测试,看下效果。

    @Test
    public void abstractExecutionThreadServiceTest() {
        // 定义我们自定义的AbstractExecutionThreadServiceImpl的类对象
        AbstractExecutionThreadServiceImpl service = new AbstractExecutionThreadServiceImpl();
        // 添加状态监听
        service.addListener(new Service.Listener() {
            @Override
            public void starting() {
                System.out.println("服务开始启动");
            }

            @Override
            public void running() {
                System.out.println("服务开始运行");
            }

            @Override
            public void stopping(Service.State from) {
                System.out.println("服务关闭中");
            }

            @Override
            public void terminated(Service.State from) {
                System.out.println("服务终止");
            }

            @Override
            public void failed(Service.State from, Throwable failure) {
                System.out.println("失败,cause:" + failure.getCause());
            }
        }, MoreExecutors.directExecutor());
        // 启动服务
        service.startAsync().awaitRunning();
        System.out.println("服务状态为:" + service.state());
        // 等待30s
        Uninterruptibles.sleepUninterruptibly(30, TimeUnit.SECONDS);
        // 停止服务
        service.stopAsync().awaitTerminated();

        System.out.println("服务状态为:" + service.state());
    }

AbstractScheduledService

       AbstractScheduledService可以帮助我们把周期性的任务封装成一个服务。
咱们线程池不是也有一个周期性的线程池么,两者是一一对应的.

AbstractScheduledService方法介绍

       AbstractScheduledService也是一个服务所以,Service里面的方法AbstractScheduledService也都有,这些方法上面已经提到了.这里着重介绍其他的一些方法.

public class AbstractScheduledService {

    ...

    /**
     * 周期任务的具体逻辑在这个里面实现
     */
    protected abstract void runOneIteration() throws Exception;

    /**
     * 启动周期任务之前调用,我们可以在里面做一些初始化的操作
     */
    protected void startUp() throws Exception;


    /**
     * 周期任务停止之后调用,我们可以在里面做 一些释放资源的处理
     */
    protected void shutDown() throws Exception {}


    /**
     * 指定当前周期任务在哪个ScheduledExecutorService里面调用
     * Scheduler.newFixedDelaySchedule()
     */
    protected abstract Scheduler scheduler();

    ...
}

AbstractScheduledService的使用

       用一个简单的实例来说明下AbstractScheduledService的使用.自定义一个类继承AbstractScheduledService.实现一个非常简单的周期性任务.

public class AbstractScheduledServiceImpl extends AbstractScheduledService {


    @Override
    protected void startUp() throws Exception {
        //TODO: 做一些初始化操作
    }

    @Override
    protected void shutDown() throws Exception {
        //TODO: 可以做一些清理操作,比如关闭连接啥的。shutDown() 是在线程的具体实现里面调用的
    }

    @Override
    protected void runOneIteration() throws Exception {
        // 每次周期任务的执行逻辑
        try {
            System.out.println("do work....");
        } catch (Exception e) {
            //TODO: 处理异常,这里如果抛出异常,会使服务状态变为failed同时导致任务终止。
        }
    }

    @Override
    protected Scheduler scheduler() {
        // 5s执行一次的Scheduler
        return Scheduler.newFixedDelaySchedule(1, 5, TimeUnit.SECONDS);
    }
}

       单元测试,测试下.

    @Test
    public void abstractScheduledServiceImplTest() {
        // 定义AbstractScheduledServiceImpl对象
        AbstractScheduledServiceImpl service = new AbstractScheduledServiceImpl();
        // 添加状态监听器
        service.addListener(new Service.Listener() {
            @Override
            public void starting() {
                System.out.println("服务开始启动.....");
            }

            @Override
            public void running() {
                System.out.println("服务开始运行");
            }

            @Override
            public void stopping(Service.State from) {
                System.out.println("服务关闭中");
            }

            @Override
            public void terminated(Service.State from) {
                System.out.println("服务终止");
            }

            @Override
            public void failed(Service.State from, Throwable failure) {
                System.out.println("失败,cause:" + failure.getCause());
            }
        }, MoreExecutors.directExecutor());
        // 启动任务
        service.startAsync().awaitRunning();
        System.out.println("服务状态为:" + service.state());

        // 等待30s
        Uninterruptibles.sleepUninterruptibly(30, TimeUnit.SECONDS);

        // 关闭任务
        service.stopAsync().awaitTerminated();
        System.out.println("服务状态为:" + service.state());
    }

ServiceManager

       ServiceManager是用来管理多个服务的,让对多个服务的操作变的更加荣一,比如咱们可以同时去启动多个服务,同时去停止多个服务等等.

ServiceManager常用方法介绍

public class ServiceManager {

    /**
     * 构造函数,管理多个Service服务
     */
    public ServiceManager(Iterable<? extends Service> services);

    /**
     * 给ServiceManager增加状态监听器
     */
    public void addListener(Listener listener, Executor executor);
    public void addListener(Listener listener);

    /**
     * 开始启动ServiceManager里面所有Service服务
     */
    public ServiceManager startAsync();

    /**
     * 等待ServiceManager里面所有Service服务达到Running状态
     */
    public void awaitHealthy();
    public void awaitHealthy(long timeout, TimeUnit unit) throws TimeoutException;

    /**
     * 停止ServiceManager里面所有Service服务
     */
    public ServiceManager stopAsync();

    /**
     * 等待ServiceManager里面所有Service服务达到终止状态
     */
    public void awaitStopped();
    public void awaitStopped(long timeout, TimeUnit unit) throws TimeoutException;

    /**
     * ServiceManager里面所有Service服务是否都达到了Running状态
     */
    public boolean isHealthy();

    /**
     * 以状态为索引返回当前所有服务的快照
     */
    public ImmutableMultimap<State, Service> servicesByState();

    /**
     * 返回一个Map对象,记录被管理的服务启动的耗时、以毫秒为单位,同时Map默认按启动时间排序
     */
    public ImmutableMap<Service, Long> startupTimes();

}

ServiceManager的使用

       我们用一个简单的实例,来管理咱们上面实现的AbstractExecutionThreadServiceImpl和AbstractScheduledServiceImpl类.代码如下.

    @Test
    public void serviceManagerTest() {
        // 定义两个服务
        AbstractExecutionThreadServiceImpl service0 = new AbstractExecutionThreadServiceImpl();
        AbstractScheduledServiceImpl service1 = new AbstractScheduledServiceImpl();
        List<Service> serviceList = Lists.newArrayList(service0, service1);
        // ServiceManager里面管理这两个服务
        ServiceManager serviceManager = new ServiceManager(serviceList);
        // 添加监听
        serviceManager.addListener(new ServiceManager.Listener() {
            @Override
            public void healthy() {
                super.healthy();
                System.out.println("healthy");
            }

            @Override
            public void stopped() {
                super.stopped();
                System.out.println("stopped");
            }

            @Override
            public void failure(Service service) {
                super.failure(service);
                System.out.println("failure");
            }
        });
        // 启动服务,等待所有的服务都达到running状态
        serviceManager.startAsync().awaitHealthy();
        // 等待30s
        Uninterruptibles.sleepUninterruptibly(30, TimeUnit.SECONDS);
        // 停止服务
        serviceManager.stopAsync().awaitStopped();
    }

       到这里,我们就把Guava里面的Service服务框架做了一个非常简单的介绍,也希望能帮助到大家,如果大家有什么不明白的地方,或者源码有哪里不明白的地方可以留言.也是强烈建议大家去看看源码特别是AbstractService,AbstractExecutionThreadService,AbstractScheduledService这三个类的具体实现.

相关文章

网友评论

    本文标题:Google Guava Service(服务)简单介绍

    本文链接:https://www.haomeiwen.com/subject/heevcctx.html