成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

spring statemachine的企業(yè)可用級開發(fā)指南6-持久化

Jioby / 3057人閱讀

摘要:目前為止,我們都是從狀態(tài)流程的開始階段創(chuàng)建一個狀態(tài)機(jī),然后一路走下去。然后就可以愉快的在里面看怎么用了發(fā)送事件持久化恢復(fù)狀態(tài)機(jī)后的狀態(tài)為執(zhí)行完保存后,大家可以自己在客戶端查看以下,是不是有內(nèi)容保存進(jìn)去了。

目前為止,我們都是從狀態(tài)流程的開始階段創(chuàng)建一個狀態(tài)機(jī),然后一路走下去。但在實(shí)際業(yè)務(wù)中,狀態(tài)機(jī)可能需要在某個環(huán)節(jié)停留,等待其他業(yè)務(wù)的觸發(fā),然后再繼續(xù)下面的流程。比如訂單,可能在支付環(huán)節(jié)需要等待一個剁手的用戶隔天再下單,所以這里面涉及到一個創(chuàng)建的狀態(tài)機(jī)該何去何從的問題。在spring statemachine中,給出來的辦法就是保存起來,到需要的時候取出來用。

1、持久化到本地內(nèi)存
嚴(yán)格來說,你完全可以自己保存狀態(tài)機(jī),比如我就自己用map保存下來了。

public class MachineMap {

public static Map> orderMap = new HashMap>();
public static Map> formMap = new HashMap>();

}
這個代碼一看就明白,我用唯一id作為key(order就是orderId,form就是formId),把狀態(tài)機(jī)保存到map表里面,在實(shí)際的業(yè)務(wù)中,自由存取

@RequestMapping("/sendEvent")

void sendEvent(String machineId,String events,String id) throws Exception{
    if(machineId.equals("form")) {
        StateMachine sm = MachineMap.formMap.get(id);
        Form form = new Form();
        form.setId(id);
        if(sm == null) {
            if(events.equals("WRITE")) {
                sm = formStateMachineBuilder.build(beanFactory);
                sm.start();
                MachineMap.formMap.put(id, sm);
            }else {
                System.out.println("該表單流程尚未開始,不能做"+events+"轉(zhuǎn)換");
                return;
            }
        }
        
        Message message = MessageBuilder.withPayload(FormEvents.valueOf(events)).setHeader("form", form).build();
        sm.sendEvent(message);
    }
    if(machineId.equals("order")) {
        StateMachine sm = MachineMap.orderMap.get(id);
        Order order = new Order();
        order.setId(id);
        if(sm == null) {
            if(events.equals("PAY")) {
                sm = orderStateMachineBuilder.build(beanFactory);
                sm.start();
                MachineMap.orderMap.put(id, sm);
            }else {
                System.out.println("該訂單流程尚未開始,不能做"+events+"轉(zhuǎn)換");
                return;
            }
            
        }
        Message message = MessageBuilder.withPayload(OrderEvents.valueOf(events)).setHeader("order", order).setHeader("test","test1").build();
        sm.sendEvent(message);
    }
}

在這段代碼里面,我根據(jù)不同種類的狀態(tài)機(jī)去map取和id對應(yīng)的狀態(tài)機(jī),如果狀態(tài)機(jī)沒在map里面,就創(chuàng)建一個,然后塞進(jìn)map表。其實(shí)寫這個代碼,并沒有其他意思,只是為了告訴你,spring打算管理你的map表,所以出了一個接口來規(guī)范這件事:

import java.util.HashMap;
import java.util.Map;

import org.springframework.statemachine.StateMachineContext;
import org.springframework.statemachine.StateMachinePersist;
import org.springframework.stereotype.Component;

/**

在內(nèi)存中持久化狀態(tài)機(jī)

*/
@Component
public class InMemoryStateMachinePersist implements StateMachinePersist {

private Map> map = new HashMap>();

@Override
public void write(StateMachineContext context, String contextObj) throws Exception {
    map.put(contextObj, context);
}

@Override
public StateMachineContext read(String contextObj) throws Exception {
    return map.get(contextObj);
}

}
這個接口非常簡單,就是write和read,但他保存的對象是StateMachineContext,不是StateMachine,所以我們還不能直接用它,需要配置一下。

import org.springframework.statemachine.StateMachinePersist;
......
import org.springframework.statemachine.persist.StateMachinePersister;
@Configuration
public class PersistConfig {


@Autowired
private InMemoryStateMachinePersist inMemoryStateMachinePersist;

/**
 * 注入StateMachinePersister對象
 * 
 * @return
 */
@Bean(name="orderMemoryPersister")
public StateMachinePersister getPersister() {
    return new DefaultStateMachinePersister<>(inMemoryStateMachinePersist);
}

}
這里有個坑,InMemoryStateMachinePersist 實(shí)現(xiàn)的接口是

org.springframework.statemachine.StateMachinePersist
,但在PersistConfig 里面,getPersister()方法返回的值類型是StateMachinePersister類型,看著很像,但并不是上面的這個接口,而是org.springframework.statemachine.persist.StateMachinePersister接口,為了表示這個坑對我的傷害,我要強(qiáng)調(diào)一下兩個接口:

package org.springframework.statemachine;
public interface StateMachinePersist {

void write(StateMachineContext context, T contextObj) throws Exception;
StateMachineContext read(T contextObj) throws Exception;

}
package org.springframework.statemachine.persist;
import org.springframework.statemachine.StateMachine;
public interface StateMachinePersister {

void persist(StateMachine stateMachine, T contextObj) throws Exception;
StateMachine restore(StateMachine stateMachine, T contextObj) throws Exception;

}
這兩個接口名字很類似,很容易搞混,但下面的是有er的,包名也不同的。StateMachinePersister是可以直接保存StateMachine對象的,所以我們需要先實(shí)現(xiàn)上面的StateMachinePersist,然后再一個Config類里面轉(zhuǎn)換成下面的StateMachinePersister,轉(zhuǎn)換的代碼就在上面的PersistConfig類里。

然后我們就能在controller里面使用了

@Resource(name="orderMemoryPersister")
private StateMachinePersister orderMemorypersister;

......

//保存狀態(tài)機(jī)
@RequestMapping("/testMemoryPersister")

public void tesMemorytPersister(String id) throws Exception {
    StateMachine stateMachine = orderStateMachineBuilder.build(beanFactory);
    stateMachine.start();
    
    //發(fā)送PAY事件
    stateMachine.sendEvent(OrderEvents.PAY);
    Order order = new Order();
    order.setId(id);
    
    //持久化stateMachine
    orderMemorypersister.persist(stateMachine, order.getId());

}

//取出狀態(tài)機(jī)
@RequestMapping("/testMemoryPersisterRestore")

public void testMemoryRestore(String id) throws Exception {
    StateMachine stateMachine = orderStateMachineBuilder.build(beanFactory);
    orderMemorypersister.restore(stateMachine, id);
    System.out.println("恢復(fù)狀態(tài)機(jī)后的狀態(tài)為:" + stateMachine.getState().getId());
}

2、持久化到redis
真正的業(yè)務(wù)中,一般都是多臺機(jī)分布式運(yùn)行,所以如果狀態(tài)機(jī)只能保存在本地內(nèi)容,就不能用在分布式應(yīng)用上了。spring提供了一個方便的辦法,使用redis解決這個問題。讓我們看看怎么弄。

pom文件引入spring-statemachine-redis

    
        org.springframework.statemachine
        spring-statemachine-redis
        1.2.9.RELEASE
    

在springboot配置文件里面加上redis參數(shù),我這是application.properties

REDIS (RedisProperties) Redis數(shù)據(jù)庫索引(默認(rèn)為0)

spring.redis.database=0

Redis服務(wù)器地址

spring.redis.host=localhost

Redis服務(wù)器連接端口

spring.redis.port=6379

Redis服務(wù)器連接密碼(默認(rèn)為空)

spring.redis.password=

連接池最大連接數(shù)(使用負(fù)值表示沒有限制)

spring.redis.pool.max-active=8

連接池最大阻塞等待時間(使用負(fù)值表示沒有限制)

spring.redis.pool.max-wait=-1

連接池中的最大空閑連接

spring.redis.pool.max-idle=8

連接池中的最小空閑連接

spring.redis.pool.min-idle=0

連接超時時間(毫秒)

spring.redis.timeout=0
保證配置的redis開啟并能用,我們繼續(xù)?;氐轿覀兪煜さ腜ersistConfig

@Configuration
public class PersistConfig {

@Autowired
private RedisConnectionFactory redisConnectionFactory;


/**
 * 注入RedisStateMachinePersister對象
 * 
 * @return
 */
@Bean(name = "orderRedisPersister")
public RedisStateMachinePersister redisPersister() {
    return new RedisStateMachinePersister<>(redisPersist());
}

/**
 * 通過redisConnectionFactory創(chuàng)建StateMachinePersist
 * 
 * @return
 */
public StateMachinePersist redisPersist() {
    RedisStateMachineContextRepository repository = new RedisStateMachineContextRepository<>(redisConnectionFactory);
    return new RepositoryStateMachinePersist<>(repository);
}

}
這個套路和上面保存到本地內(nèi)存是一樣一樣的,先生成一個StateMachinePersist,這里是通過RedisConnectionFactory生成RepositoryStateMachinePersist,然后再包裝輸出StateMachinePersister,這里是RedisStateMachinePersister。然后就可以愉快的在controller里面看怎么用了

@Resource(name="orderRedisPersister")
private StateMachinePersister orderRedisPersister;

......

@RequestMapping("/testRedisPersister")

public void testRedisPersister(String id) throws Exception {
    StateMachine stateMachine = orderStateMachineBuilder.build(beanFactory);
    stateMachine.start();
    Order order = new Order();
    order.setId(id);
    //發(fā)送PAY事件
    Message message = MessageBuilder.withPayload(OrderEvents.PAY).setHeader("order", order).build();
    stateMachine.sendEvent(message);
    //持久化stateMachine
    orderRedisPersister.persist(stateMachine, order.getId());
}

@RequestMapping("/testRedisPersisterRestore")
public void testRestore(String id) throws Exception {
    StateMachine stateMachine = orderStateMachineBuilder.build(beanFactory);
    orderRedisPersister.restore(stateMachine, id);
    System.out.println("恢復(fù)狀態(tài)機(jī)后的狀態(tài)為:" + stateMachine.getState().getId());
}

執(zhí)行完redis保存statemachine后,大家可以自己在redis客戶端查看以下,是不是有內(nèi)容保存進(jìn)去了。

3、下期預(yù)告
無論是本地內(nèi)存還是分布式緩存,似乎都不是很可靠的持久化,但下一章會告訴大家,保不保存也就那么點(diǎn)大的事,沒保存我們就再創(chuàng)建一個就好了。但另外一個問題就浮出水面了,狀態(tài)機(jī)執(zhí)行到中間的時候創(chuàng)建狀態(tài)機(jī),怎么在中間繼續(xù)執(zhí)行,之前的可都是從頭開始執(zhí)行的,這個問題,下一章解決。

碼云配套代碼地址

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/74992.html

相關(guān)文章

  • spring statemachine企業(yè)可用開發(fā)指南7-偽久化和中間段狀態(tài)機(jī)

    摘要:在實(shí)際的企業(yè)開發(fā)中,不可能所有情況都是從頭到尾的按狀態(tài)流程來,會有很多意外,比如歷史數(shù)據(jù),故障重啟后的遺留流程,所以這種可以任意調(diào)節(jié)狀態(tài)的才是我們需要的狀態(tài)機(jī)。 1、偽持久化和中間段的狀態(tài)機(jī)我們設(shè)想一個業(yè)務(wù)場景,就比如訂單吧,我們一般的設(shè)計(jì)都會把訂單狀態(tài)存到訂單表里面,其他的業(yè)務(wù)信息也都有表保存,而狀態(tài)機(jī)的主要作用其實(shí)是規(guī)范整個訂單業(yè)務(wù)流程的狀態(tài)和事件,所以狀態(tài)機(jī)要不要保存真的不重要,...

    shiyang6017 評論0 收藏0
  • spring statemachine企業(yè)可用開發(fā)指南5-傳遞參數(shù)message

    摘要:創(chuàng)建了后,狀態(tài)機(jī)就可以不只是傳一個,可以組合和數(shù)據(jù)內(nèi)容一起發(fā)送給狀態(tài)機(jī)變化的處理類了。到這里為止,狀態(tài)機(jī)通過對象就和其他的業(yè)務(wù)代碼做到了數(shù)據(jù)連接。 在企業(yè)開發(fā)中,數(shù)據(jù)在不同的業(yè)務(wù)間傳輸是最常見的工作,所以雖然我們的主架構(gòu)是用的狀態(tài)機(jī),也就是從流程狀態(tài)的角度來看待這個項(xiàng)目,但在具體業(yè)務(wù)中,每個狀態(tài)的轉(zhuǎn)變中會牽涉到各類業(yè)務(wù),這些業(yè)務(wù)有些需要收到狀態(tài)機(jī)變化的通知,需要把狀態(tài)值傳遞給業(yè)務(wù)類和業(yè)...

    YacaToy 評論0 收藏0
  • spring statemachine企業(yè)可用開發(fā)指南3-多個狀態(tài)機(jī)共存

    摘要:雖然多個狀態(tài)機(jī)的問題解決了,但是對于實(shí)際的企業(yè)應(yīng)用而言,還是有問題。這個問題就用到了狀態(tài)機(jī)的持久化,我們下一章就談?wù)劤志没瘑栴}。 1、多個狀態(tài)機(jī)的搞法在實(shí)際的企業(yè)應(yīng)用中,基本不可能只有一個狀態(tài)機(jī)流程在跑,比如訂單,肯定是很多個訂單在運(yùn)行,每個訂單都有自己的訂單狀態(tài)機(jī)流程,但上一章的例子,大家可以試一下,當(dāng)執(zhí)行到一個狀態(tài)時,再次刷新頁面,不會有任何日志出現(xiàn),當(dāng)一個狀態(tài)流程執(zhí)行到某個狀態(tài),...

    zhongmeizhi 評論0 收藏0
  • spring statemachine企業(yè)可用開發(fā)指南1-說些廢話

    摘要:讓我們先看下狀態(tài)機(jī)的概念。下面是狀態(tài)機(jī)模型中的個要素,即現(xiàn)態(tài)條件動作次態(tài)。因?yàn)橛唵魏蛯徟亩加泻芏嗟牧鞒蹋總€流程都會產(chǎn)生狀態(tài)的變化,而且流程是這種業(yè)務(wù)的主軸,其他都是圍繞這個流程和狀態(tài)變化來考慮的,所以看起來蠻適合用狀態(tài)機(jī)來做。 1、背景在我打算學(xué)習(xí)spring statemachine的時候,我?guī)缀蹩催^了所有網(wǎng)上的中文教程,基本上都處于淺嘗輒止的階段,有幾篇講的比較深入的,都只是...

    BakerJ 評論0 收藏0
  • spring statemachine企業(yè)可用開發(fā)指南4-多種狀態(tài)機(jī)共存

    摘要:目前為止,多個狀態(tài)機(jī)和多種狀態(tài)機(jī)都可以在里面實(shí)現(xiàn)了,下一章我們來解決下狀態(tài)機(jī)和實(shí)際業(yè)務(wù)間的數(shù)據(jù)傳輸問題,畢竟我們不是為了讓狀態(tài)機(jī)自個獨(dú)自玩耍,和業(yè)務(wù)數(shù)據(jù)互通有無才是企業(yè)開發(fā)的正道。 在上一章的例子中,我們實(shí)現(xiàn)了多個狀態(tài)機(jī)并存執(zhí)行,不同的訂單有各自的狀態(tài)機(jī)運(yùn)行,但只有一種狀態(tài)機(jī),這顯然不能滿足實(shí)際業(yè)務(wù)的要求,比如我就遇到了訂單流程和公文審批流程在同一個項(xiàng)目的情況,所以我們這一章講怎么讓多...

    boredream 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<