首页 > 其他分享 >jvm shutdownHook + spring 自定义事件实现业务处理

jvm shutdownHook + spring 自定义事件实现业务处理

时间:2024-02-14 09:13:34浏览次数:25  
标签:java String 自定义 spring shutdownHook System println public

jvm 的shutdownHook 可以实现对于jvm 退出的一些处理,比如资源清理,异常事件通知,spring 自定义事件(或者使用内部的)可以实现
bean 的一些事件驱动处理,两个结合起来可以方便我们进行一些业务处理

一些业务场景

  • 资源清理
  • 服务停止业务状态一致性补偿
  • 服务注册场景中的取消注册
  • 服务停止业务处理

简单使用

  • 项目结构
├── HELP.md
├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── dalong
    │   │           └── shutdowndemo
    │   │               ├── Api.java
    │   │               ├── BizA.java
    │   │               ├── BizB.java
    │   │               ├── BizC.java
    │   │               ├── EventHook.java
    │   │               ├── MyEvent.java
    │   │               └── ShutdowndemoApplication.java
    │   └── resources
    │       ├── application.properties
    │       ├── static
    │       └── templates
  • 代码简单说明
    ShutdowndemoApplication为spring boot 的入口,Api业务接口(rest api 入口),BizA,BizB,BizC 是业务服务,
    EventHook 一个spring 系统的事件处理,MyEvent 自定义事件
  • ShutdowndemoApplication.java
@SpringBootApplication
public class ShutdowndemoApplication {
    private  static ApplicationContext applicationContext;
    public static void main(String[] args) {
        applicationContext= SpringApplication.run(ShutdowndemoApplication.class, args);
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.out.println("Shutting down");
            MyEvent myEvent = new MyEvent("1.0.0");
            myEvent.setName("dalong");
            myEvent.setVersion("1.0.0");
            applicationContext.publishEvent(myEvent);
        } ));
    }
}

Api.java 主要是调用业务服务,同时实现了spring 系统事件,可以进行一些处理

@RestController
public class Api implements ApplicationListener<ContextClosedEvent> {
 
    @Autowired
    private BizA bizA;
 
    @Autowired
    private BizB bizB;
   
    @Autowired
    private BizC bizC;
 
    @GetMapping(value = {"/demo"})
    public String demo() {
        String a = bizA.acitonA();
        String b = bizB.actionB();
        String c = bizC.actionC();
        return a + b + c;
    }
 
    private void doClean() {
        try {
            System.out.println("Api doClean start");
            Thread.sleep(3000);
            System.out.println("Api doClean end");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
 
    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        System.out.println("Api onApplicationEvent Shutting down");
        doClean();
    }
}

BizA.java (其他的b,c 都比较类似)

@Service
public class BizA implements ApplicationListener<ContextClosedEvent> {
    public String doBiz() {
        try {
            System.out.println("doBizA biz start");
            Thread.sleep(6000);
            System.out.println("doBizA biz end");
            return "doBizA biz end";
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
 
    public String acitonA() {
        return "actionA";
    }
 
    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        System.out.println("BizA onApplicationEvent Shutting down");
        doBiz();
    }
}

EventHook.java

@Component
public class EventHook implements ApplicationListener<ContextClosedEvent> {
    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        try {
            System.out.println("onApplicationEvent Shutting down");
            Thread.sleep(1000);
            System.out.println("onApplicationEvent biz end");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
 
    @Override
    public boolean supportsAsyncExecution() {
        return ApplicationListener.super.supportsAsyncExecution();
    }
}

MyEvent.java

public class MyEvent extends ApplicationEvent {
    private String name;
    private String version;
 
    public MyEvent(Object source) {
        super(source);
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getVersion() {
        return version;
    }
 
    public void setVersion(String version) {
        this.version = version;
    }
}

运行效果

如果实际我们执行kill <jvm pid>,效果如下

说明

以上只是一个简单的演示,实际上如果我们想更好的基于jvm shutdownHook + spring 进行一些业务系统的处理,比如业务务感知的业务滚动升级处理,实际上有不少东西要处理,比如服务的prestop 阶段的的处理,同时业务请求流量的处理,业务一致性的保证,但是基于spring 以及jvm 提供的一些
完整测试代码我已经push 到github 了可以参考
能力可以简化我们的实际实现

参考资料

https://docs.oracle.com/javase/8/docs/technotes/guides/lang/hook-design.html
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationListener.html
https://www.baeldung.com/spring-events
https://www.baeldung.com/spring-boot-enable-disable-endpoints-at-runtime

标签:java,String,自定义,spring,shutdownHook,System,println,public
From: https://www.cnblogs.com/rongfengliang/p/18012321

相关文章

  • Java与SpringBoot网站的重构
    Java简介Java特点: Java的运行原理: SpringBoot网站的重构有源码的情况后台重构(mysql+maven+jdk+网站源码)将网站源码放入idea软件中查看重要配置文件:pom.xml和application.propertiespom.xml有网站的jdk版本和打包软件而application.properites文件中有着数据库的配......
  • springboot自定义starter 版本大于2.7
    相关jar包<!--提示配置--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><version>3.2.1</versi......
  • qt自定义标题栏,纯代码实现,拿来即用,初始化列表时传入父窗口的this指针
    //头文件#ifndefTITLEBAR_H#defineTITLEBAR_H#include<QWidget>#include<QPoint>//坐标点#include<QMouseEvent>//鼠标事件classTitleBar:publicQWidget{Q_OBJECTpublic:explicitTitleBar(QWidget*parent=nullptr);//移动窗口......
  • 大年初二学习SpringBoot之权限管理
    1增加spring-security依赖目前市面上主流的权限框架是:spring-security和shiro,shrio使用起来更简单,而spring-security的功能更强大。苏三商城项目选择的权限框架是:spring-security。首先要加入spring-security的相关依赖包。在项目中的pom.xml文件中增加如下依赖:<dependency......
  • springboot整合redis报错:链接失败;org.springframework.data.redis.RedisConnectionFai
    错误原因:开启了保护模式解决方案:关闭保护模式和防火墙具体步骤:1、打开你的redis配置文件,做出如下修改2.开启进程守护yes代表开启守护进程模式。在该模式下,redis会在后台运行,并将进程pid号写入至redis.conf选项pidfile设置的文件中,此时redis将一直运行,除非手动kill该进程。3.......
  • 抛弃Spring Cloud Gateway,得物 使用Netty架构100Wqps网关
    文章很长,且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录博客园版为您奉上珍贵的学习资源:免费赠送:《尼恩Java面试宝典》持续更新+史上最全+面试必备2000页+面试必备+大厂必备+涨薪必备免费赠送:《尼恩技术圣经+高并发系列PDF》,帮你实现技术自由,完成职业升级,薪......
  • Springboot项目中使用Elasticsearch的RestClient
    上一篇介绍了Elasticsearch的入门《5000字详说Elasticsearch入门(一)》,本篇介绍Springboot如何集成使用Elasticsearch。分为3步:配置properties文件、引入pom依赖、配置RestHighLevelClient类。1、选择ES的ClientAPI我们知道Elasticsearch是一款RestfulAPI风格的分布式搜索引擎......
  • SpringMVC 教程
    SpringMVC回顾MVC什么是MVCMVC是:模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范;是将业务逻辑、数据、显示分离的方法来组织代码;MVC的主要作用是降低了视图与业务逻辑间的双向耦合;MVC不是一种设计模式,MVC是一种架构模式。Model:数据模型......
  • [spring] spring学习笔记(3): 通过注解实现依赖注入
    注解Annotation注解是代码中的一种特殊标记,java中的格式为@Anno_Name(pro=value)注解可以被使用在方法,类和属性上;在spring中,使用注解来实现自动装配,可以简化Bean的配置,基本步骤如下:引入依赖开启组件扫描使用注解定义Bean注入依赖引入依赖在新建的spring项目下的src/main......
  • elsa-core自定义Activity创建Bookmark人工任务完成
    //实现一个自定的activity用于人工处理的节点publicclassMyRunTask:Activity<object>{[Input(Description="Thenameofthetaskbeingrequested.")]publicInput<string>TaskName{get;set;}=default!;///<inheritdo......