前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >springboot实战之创建一个支持平滑关闭的非web项目

springboot实战之创建一个支持平滑关闭的非web项目

作者头像
lyb-geek
发布2019-12-24 17:10:36
2.2K0
发布2019-12-24 17:10:36
举报
文章被收录于专栏:Linyb极客之路Linyb极客之路

前言

之前在springboot项目启动不报错,但一启动就断开连接问题排查实录一文中,留了一个小尾巴。即如何在springboot项目中不引入web包,也能实现项目启动后,后台能不停止,能一直运行?答案很简单:不让程序停止,那就让主程序一直卡着,官方术语就是,让主程序处于堵塞状态。那如何让主程序处于堵塞状态呢?学过java的同学,main()方法是Java应用程序的入口方法,也就是说,程序在运行的时候,第一个执行的方法就是main()方法。那就在入口处,加个堵塞代码片段就行了。下边就写个简单示例来演示下

创建非web项目流程

1、在启动主程序中,加入堵塞代码片段

堵塞的代码有多种多样,常用的有如下方案

a、写个无限循环方法。不过这种方式不建议使用,太浪费cpu内存

b、利用并发包下提供的一些工具,比如Semaphore。这种实现不占用cpu内存

代码语言:javascript
复制
Semaphore semaphore = new Semaphore(0);
    try {
      semaphore.acquire();
    } catch (InterruptedException e) {
      log.error(e.getMessage(),e);
    }

c、添加io堵塞片段,比如socket连接代码,最简单的堵塞io片段是如下

代码语言:javascript
复制
System.in.read();

按上述方法实现后,启动项目后,就可以一直处于后台运行。

有启动,就有关闭,在linux环境中,我们关闭一个项目,可能会执行 kill -9 pid把进程关闭。然而这种关闭对业务可能是有损的,比如你后台程序在跑业务线程,此时执行kill -9 pid,就可能会导致业务逻辑处理中断,导致业务出错。因此我们需要一种能平滑关闭的的机制来关闭项目。这边提供两种关闭方案

2、平滑关闭代码

a、在程序中添加addShutdownHook方法

这个方法的意思就是在jvm中增加一个关闭的钩子,当jvm关闭的时候,会执行系统中已经设置的所有通过方法addShutdownHook添加的钩子,当系统执行完这些钩子后,jvm才会关闭。所以这些钩子可以在jvm关闭的时候进行内存清理、对象销毁、关闭连接等操作。addShutdownHook遇到如下场景会被调用

  • 程序正常退出
  • 使用System.exit()
  • 终端使用Ctrl+C触发的中断
  • 系统关闭
  • OutOfMemory宕机
  • 使用kill pid

示例代码

代码语言:javascript
复制
public void release(Runnable runnable){
    Runtime.getRuntime().addShutdownHook(new Thread(runnable));
  }

b、程序中通过Signal类注册信号监听kill信号,在Linux下支持的信号(具体信号kill -l命令查看)

示例代码

代码语言:javascript
复制
public class ShutDownHookSignalHandler implements SignalHandler {

  @Override
  public void handle(Signal signal) {

    SignalType signalType = SignalType.getSignal(signal.getName());

    switch (signalType){
      //kill -12
      case USR2:
        callbackByUSR1();
        break;
      //kill -15
      case TERM:
        break;
    }

  }


  private void callbackByUSR1(){
    boolean isClose = ThreadPoolUtil.INSTANCE.close();
    log.info("thread pool isClose:{}",isClose);
  }

  public void registerSignal(String signalName) {
    Signal signal = new Signal(signalName);
    Signal.handle(signal, this);
  }

}

c、Signal类注册信号监听和addShutdownHook使用的区别

Signal中的handle方法会在进程被kill时收到信号,对main函数的运行不会有任何影响,而使用addShutdownHook,当进程被kill的时候main函数就已经结束了,仅会运行shutdownHook中run()方法的代码。

此外addShutdownHook方法和Signal中handle方法中如果再调用System.exit,会造成死锁,使进程无法正常退出

基于上述原因,我们就可以在代码中同时使用这两种方法

3、示例演示

a、项目启动

b、项目关闭,先执行kill -12 pid

再执行kill -15 pid

总结

创建一直运行的后台程序,主要就是保持主程序堵塞。其次通过signal监听信号量和addShutdownHook配合使用,就可以达到平滑关闭程序的效果。在开发中,可以写一个脚本,先通过kill -12,修改线程池等状态,不再接受新资源,待原有资源处理完毕后。执行kill -15,关闭所有连接,并进行后续一些操作

demo链接

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-exclude-web

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Linyb极客之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 创建非web项目流程
  • 总结
  • demo链接
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档