• spring-statemachine 状态机自定义持久化入库


    使用 spring-statemachine 状态机持久化时,可以通过内存、spring-statemachine-redis 或 spring-statemachine-data-jpa 现有方式持久化处理。

    因项目审核操作记录频繁,数据量大,使用 内存 或 spring-statemachine-redis 模式不可取,而项目使用的是 MyBatis,使用 spring-statemachine-data-jpa 也不合适,需要自定义实现,简述步骤如下:

    一、引入依赖

    1. <dependency>
    2. <groupId>org.springframework.statemachinegroupId>
    3. <artifactId>spring-statemachine-starterartifactId>
    4. <version>2.2.3.RELEASEversion>
    5. dependency>
    6. <dependency>
    7. <groupId>org.springframework.statemachinegroupId>
    8. <artifactId>spring-statemachine-kryoartifactId>
    9. <version>1.2.14.RELEASEversion>
    10. dependency>

    二、创建持久化记录存储表

    1. CREATE TABLE `state_machine_context` (
    2. `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增主键',
    3. `machine_type` VARCHAR (32) DEFAULT '' COMMENT '状态机类型',
    4. `machine_id` VARCHAR (36) DEFAULT '' COMMENT '状态机ID',
    5. `machine_data` TINYBLOB COMMENT '状态机数据',
    6. `machine_state` VARCHAR (32) DEFAULT '' COMMENT '状态机状态',
    7. `machine_event` VARCHAR (36) DEFAULT '' COMMENT '状态机事件',
    8. `create_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    9. `update_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
    10. PRIMARY KEY (`id`),
    11. KEY `idx_machine_id` (`machine_id`)
    12. ) ENGINE = INNODB COMMENT = '状态机上下文'

    关键字段说明 

    • machine_type:标记业务类型,如订单业务、用户业务
    • macheine_id:业务数据ID,如订单ID、用户ID
    • machine_data:状态机二进制数据

    其它字段可根据自己业务需求自定义

    三、自定义持久化类,即实现接口 StateMachinePersist

    1. import com.esotericsoftware.kryo.Kryo;
    2. import com.esotericsoftware.kryo.io.Input;
    3. import com.esotericsoftware.kryo.io.Output;
    4. import org.apache.commons.lang3.tuple.Pair;
    5. import org.springframework.messaging.MessageHeaders;
    6. import org.springframework.statemachine.StateMachineContext;
    7. import org.springframework.statemachine.StateMachinePersist;
    8. import org.springframework.statemachine.kryo.MessageHeadersSerializer;
    9. import org.springframework.statemachine.kryo.StateMachineContextSerializer;
    10. import org.springframework.statemachine.kryo.UUIDSerializer;
    11. import java.io.ByteArrayInputStream;
    12. import java.io.ByteArrayOutputStream;
    13. import java.util.Date;
    14. import java.util.Objects;
    15. import java.util.Optional;
    16. import java.util.UUID;
    17. /**
    18. * @author songjianyong
    19. */
    20. public class CustomStateMachinePersist implements StateMachinePersist> {
    21. private static final ThreadLocal KRYO_THREAD_LOCAL = ThreadLocal.withInitial(() -> {
    22. Kryo kryo = new Kryo();
    23. kryo.addDefaultSerializer(StateMachineContext.class, new StateMachineContextSerializer());
    24. kryo.addDefaultSerializer(MessageHeaders.class, new MessageHeadersSerializer());
    25. kryo.addDefaultSerializer(UUID.class, new UUIDSerializer());
    26. return kryo;
    27. });
    28. private byte[] serialize(StateMachineContext context) {
    29. Kryo kryo = KRYO_THREAD_LOCAL.get();
    30. ByteArrayOutputStream out = new ByteArrayOutputStream();
    31. Output output = new Output(out);
    32. kryo.writeObject(output, context);
    33. output.close();
    34. return out.toByteArray();
    35. }
    36. @SuppressWarnings("unchecked")
    37. private StateMachineContext deserialize(byte[] data) {
    38. if (data == null || data.length == 0) {
    39. return null;
    40. }
    41. Kryo kryo = KRYO_THREAD_LOCAL.get();
    42. ByteArrayInputStream in = new ByteArrayInputStream(data);
    43. Input input = new Input(in);
    44. return kryo.readObject(input, StateMachineContext.class);
    45. }
    46. private final StateMachineContextDao stateMachineContextDao;
    47. public SongStateMachinePersist(StateMachineContextDao stateMachineContextDao) {
    48. this.stateMachineContextDao = stateMachineContextDao;
    49. }
    50. @Override
    51. public void write(StateMachineContext context, Pair pair) throws Exception {
    52. byte[] machineData = serialize(context);
    53. String machineId = pair.getKey();
    54. String machineType = pair.getValue();
    55. StateMachineContextEntity stateMachineContexEntity = stateMachinePersistDao.findByMachineIdAndMachineType(machineId, machineType);
    56. if (Objects.nonNull(stateMachineContexEntity)) {
    57. stateMachineContexEntity.setMachineData(machineData);
    58. stateMachineContexEntity.setMachineState(Optional.ofNullable(context.getState()).map(Objects::toString).orElse(stateMachineContexEntity.getMachineState()));
    59. stateMachineContexEntity.setMachineEvent(Optional.ofNullable(context.getEvent()).map(Objects::toString).orElse(stateMachineContexEntity.getMachineEvent()));
    60. stateMachineContexEntity.setUpdateDate(new Date());
    61. stateMachineContextDao.updateById(stateMachineContexEntity);
    62. return;
    63. }
    64. StateMachineContextEntity entity = new StateMachineContextEntity();
    65. entity.setMachineId(machineId);
    66. entity.setMachineData(machineData);
    67. entity.setMachineType(machineType);
    68. entity.setMachineState(Optional.ofNullable(context.getState()).map(Objects::toString).orElse(null));
    69. entity.setMachineEvent(Optional.ofNullable(context.getEvent()).map(Objects::toString).orElse(null));
    70. stateMachineContextDao.save(entity);
    71. }
    72. @Override
    73. public StateMachineContext read(Pair pair) throws Exception {
    74. String machineId = pair.getKey();
    75. String machineType = pair.getValue();
    76. StateMachineContextEntity stateMachineContexEntity = stateMachineContextDao.findByMachineIdAndMachineType(machineId, machineType);
    77. if (Objects.isNull(stateMachineContexEntity)) {
    78. return null;
    79. }
    80. byte[] machineData = stateMachineContexEntity.getMachineData();
    81. return deserialize(machineData);
    82. }
    83. }

    四、自定义状态机,即继承类 AbstractStateMachinePersister

    1. import org.apache.commons.lang3.tuple.Pair;
    2. import org.springframework.statemachine.StateMachinePersist;
    3. import org.springframework.statemachine.persist.AbstractStateMachinePersister;
    4. /**
    5. * @author songjianyong
    6. */
    7. public class CustomStateMachinePersister extends AbstractStateMachinePersister> {
    8. public CustomStateMachinePersister(StateMachinePersist> stateMachinePersist) {
    9. super(stateMachinePersist);
    10. }
    11. }

    五、使用自定义状态机

    1. /**
    2. * 持久化到库中
    3. *
    4. * @return 数据库持久化状态机
    5. */
    6. @Bean(name = "customStateMachinePersister")
    7. public CustomStateMachinePersister customStateMachinePersister(StateMachineContextDao stateMachineContextDao) {
    8. CustomStateMachinePersist customStateMachinePersist = new CustomStateMachinePersist<>(stateMachineContextDao);
    9. return new CustomStateMachinePersister<>(customStateMachinePersist);
    10. }
    1. @Resource
    2. private StateMachinePersister pair> customStateMachinePersister;

  • 相关阅读:
    GitHub标星75k,阿里15W字的Spring高级文档(全彩版),真的太香了
    macOS、Linux CentOS 、Docker安装部署canal-server(canal-deployer)服务
    YGG 和 BlockchainSpace 举办全国最大的 Web3 活动:Philippine Web3 Festival
    VMware虚拟机安装Centos7系统(网络模式、桌面选择、手动分区、Kdump)
    基于Python实现的遗传算法
    Au 入门系列之二:录音
    Acwing 2944. 回家的路
    剑指 Offer 05. 替换空格 Java
    NNDL实验 优化算法3D轨迹 鱼书例题3D版
    Java InputStram/OutputStream
  • 原文地址:https://blog.csdn.net/sjy_2010/article/details/133862831