mina statemachine解读(一)

 

statemachine(状态机)在维护多状态数据时有非常好的作用,现在github上star排名最前的是squirrel-foundation以及spring-statemachine,而mina的statemachine好像并没有对外提供,多用于mina的高级特性里面。

了解了下spring-statemachine,提供特别完善的扩展方式,interceptor,listener,甚至支持分布式,但是上手使用还是有一定的难度,代码也比较复杂,状态机的实例比较重。没有看到较好的现实应用实例,如对一个任务的管理可能是需要根据ID从数据库中获取状态再根据当前状态,事件去决定transition,看到spring中是使用PersistStateMachineHandler来处理类似的情况,需要停止状态机,重置状态机为相应状态再触发,感觉不是很优雅,也可能是我看的不够深入没有理解其精髓,如果有别的实现方式欢迎留言告知。

squirrel-foundation相比较spring上手就容易很多了,有很完善的帮助示例,应用也比较符合对状态机的认知,同时也提供了完善的linstener等支持,是比较好的状态机选择。

这里主要介绍mina statemachine,相比前两个可以说寥寥无名,但是在用起来的时候还是很爽的,比较符合现实业务对状态机的要求。核心代码也就几百行,实现逻辑足够清晰,看完源码半个小时就够了,也可以根据自己的业务需求进行修改定制。

mina statemachine的guide:http://mina.apache.org/mina-project/userguide/ch14-state-machine/ch14-state-machine.html,有对应的maven gav。

先上示例吧

/**
 * 任务实体
 * @author 鱼蛮 on 2019/2/23
 **/
@Getter
@Setter
public class Task {
    /**任务ID*/
    private Integer id;
    /**任务名称*/
    private String name;
    /**任务状态*/
    private String state;
}

/**
 * @author 鱼蛮 on 2019/2/23
 **/
public interface TaskWork {
    /**
     * 任务领取
     * @param taskId
     * @param userName
     */
    void take(Integer taskId, String userName);

    /**
     * 任务提交
     * @param taskId
     */
    void submit(Integer taskId);

    /**
     * 任务审核
     * @param taskId
     * @param auditor
     */
    void audit(Integer taskId, String auditor);
}

/**
 * @author 鱼蛮 on 2019/2/23
 **/
@Slf4j
public class TaskHandler {
    @State public static final String CREATED = "Created";
    @State public static final String TOOK = "Took";
    @State public static final String SUBMITTED = "Submitted";
    @State public static final String AUDITED = "Audited";

    @Transition(on = "take", in = CREATED, next = TOOK)
    public void takeTask(StateContext context, String userName) {
        Task task = (Task)context.getAttribute("task");
        log.info("use:{},take task, taskId:{}", userName, task.getId());
    }

    @Transition(on = "submit", in = {TOOK}, next = SUBMITTED)
    public void submitTask(StateContext context) {
        Task task = (Task)context.getAttribute("task");
        log.info("taskId:{}, submitted", task.getId());
    }

    @Transition(on = "audit", in = SUBMITTED, next = AUDITED)
    public void auditTask(StateContext context, String auditor) {
        Task task = (Task)context.getAttribute("task");
        log.info("auditor:{}, audit task {}", auditor, task.getId());
    }
}

/**
 * @author 鱼蛮 on 2019/2/23
 **/
public class TaskSmTest {
    public static void main(String[] args) {
        // 新建handler
        TaskHandler taskHandler = new TaskHandler();
        // 构建状态机
        StateMachine sm = StateMachineFactory.getInstance(Transition.class).create(TaskHandler.CREATED, taskHandler);
        // 创建对外接口对象
        TaskWork taskWork = new StateMachineProxyBuilder().setStateContextLookup(new StateContextLookup() {
            @Override
            public StateContext lookup(Object[] objects) {
                Integer taskId = (Integer)objects[0];
                // 这里应该是根据Id去数据库查询
                Task task = new Task();
                task.setId(taskId);
                StateContext context = new DefaultStateContext();
                if (taskId == 123) {
                    task.setState(TaskHandler.CREATED);
                } else if (taskId == 124) {
                    task.setState(TaskHandler.TOOK);
                } else if (taskId == 125) {
                    task.setState(TaskHandler.SUBMITTED);
                }
                context.setCurrentState(sm.getState(task.getState()));
                context.setAttribute("task", task);
                return context;
            }
        }).create(TaskWork.class, sm);

        taskWork.take(123, "Jack");
        taskWork.submit(124);
        taskWork.audit(125, "Andy");

        StateContext context = new DefaultStateContext();
        context.setCurrentState(sm.getState(TaskHandler.CREATED));
        context.setAttribute("task", new Task());
        Event event = new Event("take", context, new Object[]{123, "Jack"});
        sm.handle(event);
     taskWork.submit(123);
} }

输出结果为:

2019-02-23 15:50:54,570  INFO [main] (TaskHandler.java:22) - use:Jack,take task, taskId:123
2019-02-23 15:50:54,574  INFO [main] (TaskHandler.java:28) - taskId:124, submitted
2019-02-23 15:50:54,574  INFO [main] (TaskHandler.java:34) - auditor:Andy, audit task 125
2019-02-23 15:50:54,575  INFO [main] (TaskHandler.java:22) - use:Jack,take task, taskId:null
Exception in thread "main" org.apache.mina.statemachine.event.UnhandledEventException: Unhandled event: Event[id=submit,context=StateContext[currentState=State[id=Created],attributes={task=com.blackbread.statemachine.mina.Task@4f8e5cde}],arguments={123}]
    at org.apache.mina.statemachine.StateMachine.handle(StateMachine.java:275)
    at org.apache.mina.statemachine.StateMachine.processEvents(StateMachine.java:170)
    at org.apache.mina.statemachine.StateMachine.handle(StateMachine.java:158)
    at org.apache.mina.statemachine.StateMachineProxyBuilder$MethodInvocationHandler.invoke(StateMachineProxyBuilder.java:261)
    at com.sun.proxy.$Proxy5.submit(Unknown Source)
    at com.blackbread.statemachine.mina.TaskSmTest.main(TaskSmTest.java:55)

来分析下状态机的创建以及执行流程,首先看这一行是状态机的创建,初始化

        StateMachine sm = StateMachineFactory.getInstance(Transition.class).create(TaskHandler.CREATED, taskHandler);
getInstance方法中获取传入的transitionAnnotation指定的TransitionAnnotation.class,以此作为查找trastition的注解,同时创建StateMachineFactory对象
create方法执行StateMachinne的创建
    public StateMachine create(String start, Object handler, Object... handlers) {

        Map<String, State> states = new HashMap<>();
        List<Object> handlersList = new ArrayList<>(1 + handlers.length);
        handlersList.add(handler);
        handlersList.addAll(Arrays.asList(handlers));

     // 从handler中获取带State注解的状态集合,这里必须是String类型的,如果想用其他类型的需要自己修改源码加以支持    
        LinkedList<Field> fields = new LinkedList<>();
        for (Object h : handlersList) {
            fields.addAll(getFields(h instanceof Class ? (Class<?>) h : h.getClass()));
        }     // 根据field创建State对象
        for (State state : createStates(fields)) {
            states.put(state.getId(), state);
        }

        if (!states.containsKey(start)) {
            throw new StateMachineCreationException("Start state ‘" + start + "‘ not found.");
        }
     // 执行transition与State的绑定
        setupTransitions(transitionAnnotation, transitionsAnnotation, entrySelfTransitionsAnnotation,
                exitSelfTransitionsAnnotation, states, handlersList);

        return new StateMachine(states.values(), start);
    }
private static void setupTransitions(Class<? extends Annotation> transitionAnnotation,
            Class<? extends Annotation> transitionsAnnotation,
            Class<? extends Annotation> onEntrySelfTransitionAnnotation,
            Class<? extends Annotation> onExitSelfTransitionAnnotation, Map<String, State> states, Object handler) {

        Method[] methods = handler.getClass().getDeclaredMethods();
        Arrays.sort(methods, new Comparator<Method>() {
            @Override
            public int compare(Method m1, Method m2) {
                return m1.toString().compareTo(m2.toString());
            }
        });

        for (Method m : methods) {        // 做State与OnEntry,OnExit注解标注的方法进行绑定,在进入transition以及退出时候调用
            setupSelfTransitions(m, onEntrySelfTransitionAnnotation, onExitSelfTransitionAnnotation, states, handler);

            List<TransitionWrapper> transitionAnnotations = new ArrayList<>();
            // 这里是找带有指定的transitionAnnotation注解的方法,如果是将其包装成TransitionWrapper进行保存,在下一步处理中好获取相应数据
            if (m.isAnnotationPresent(transitionAnnotation)) {
                transitionAnnotations.add(new TransitionWrapper(transitionAnnotation, m
                        .getAnnotation(transitionAnnotation)));
            }
            // 处理多个注解的
            if (m.isAnnotationPresent(transitionsAnnotation)) {
                transitionAnnotations.addAll(Arrays.asList(new TransitionsWrapper(transitionAnnotation,
                        transitionsAnnotation, m.getAnnotation(transitionsAnnotation)).value()));
            }

            if (transitionAnnotations.isEmpty()) {
                continue;
            }

            for (TransitionWrapper annotation : transitionAnnotations) {
                Object[] eventIds = annotation.on();

                if (eventIds.length == 0) {
                    throw new StateMachineCreationException("Error encountered when processing method " + m
                            + ". No event ids specified.");
                }

                if (annotation.in().length == 0) {
                    throw new StateMachineCreationException("Error encountered when processing method " + m
                            + ". No states specified.");
                }

                State next = null;

                if (!annotation.next().equals(Transition.SELF)) {
                    next = states.get(annotation.next());

                    if (next == null) {
                        throw new StateMachineCreationException("Error encountered when processing method " + m
                                + ". Unknown next state: " + annotation.next() + ".");
                    }
                }

                for (Object event : eventIds) {
                    if (event == null) {
                        event = Event.WILDCARD_EVENT_ID;
                    }

                    if (!(event instanceof String)) {
                        event = event.toString();
                    }

                    for (String in : annotation.in()) {
                        State state = states.get(in);

                        if (state == null) {
                            throw new StateMachineCreationException("Error encountered when processing method "
                                    + m + ". Unknown state: " + in + ".");
                        }
              // 这里就是执行State与Transition的绑定,定义了如下的关系:state执行了event,使用什么样的transition进行处理
                        state.addTransition(new MethodTransition(event, next, m, handler), annotation.weight());
                    }
                }
            }
        }
    }

这段代码就是创建状态机的核心代码了,其实主要了就是解析State状态集合,解析Transition标签,做State与Event,Transition的绑定,状态机在使用的时候其实就是先获取State然后通过Event查找相应的Transition进行执行了。

这里先到状态机的创建吧,再写一个状态机的内部执行流程。

原文地址:https://www.cnblogs.com/lcxdever/p/10422917.html

时间: 2024-10-06 13:03:20

mina statemachine解读(一)的相关文章

Mina State machine状态机讲解

原文地址:Mina State machine(Apache Mina User guide Chapter14 State machine) 如果您使用的是Mina与复杂网络开发应用程序交互,你可能在某些时候发现自己达到的美好状态模式尝试解决一些复杂性.然而,在你这样做之前你可能想检查mina-statemachine试图解决一些状态模式的不足之处. 1.1.1. 一个简单的例子 让我们演示mina-statemachine如何以一个简单的例子工作.下图显示了一个典型的录音机一个状态机.椭圆形

JVM源码分析之堆外内存完全解读

概述 广义的堆外内存 说到堆外内存,那大家肯定想到堆内内存,这也是我们大家接触最多的,我们在jvm参数里通常设置-Xmx来指定我们的堆的最大值,不过这还不是我们理解的Java堆,-Xmx的值是新生代和老生代的和的最大值,我们在jvm参数里通常还会加一个参数-XX:MaxPermSize来指定持久代的最大值,那么我们认识的Java堆的最大值其实是-Xmx和-XX:MaxPermSize的总和,在分代算法下,新生代,老生代和持久代是连续的虚拟地址,因为它们是一起分配的,那么剩下的都可以认为是堆外内存

mina

1.MINA是什么  MINA是apache的开源项目,是一个网络通信层封装框架.融合了多种通信协议,如:TCP/IP.UDP/IP等,采用NIO的非阻塞通信. 2.MINA的简单应用 2.1 下载相关jar包,注意日志的对应版本. mina-core-2.0.7.jar mina-example-2.0.7.jar slf4j-api-1.6.6.jar slf4j-log4j12-1.6.6.jar log4j-1.2.17.jar 2.2 服务端代码 IoAcceptor acceptor

《Netty5.0架构剖析和源码解读》【PDF】下载

<Netty5.0架构剖析和源码解读>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062545 内容简介 Netty 是个异步的事件驱动网络应用框架,具有高性能.高扩展性等特性.Netty提供了统一的底层协议接口,使得开发 者从底层的网络协议 (比如 TCP/IP. UDP) 中解脱出来. 就使用来说, 开发者只要参考Netty 提供的若干例子和它的指南文档,就可以放手开发基于 Netty 的服务端程序了. 在Java 社区,最知名的

ViewGroup源码解读

我们之前刚刚分析完事件传递机制和view的源码,如果没有看过的,建议看完View的事件拦截机制浅析以及View的事件源码解析.这次我们来分析下viewgroup的. 可能有人会想,怎么又是源码分析,肯定又是一大通.其实没你想的那么复杂.仔细分析一波就行了. 解读ViewGroup 我们都知道,一个事件完整的流程是从dispatchTouchevent–>onInterceptTouchevent–>onTouchEvent.我们先不说事件监听的问题.上述三个步骤就是正常一个点击的流程.前面我们

JAVA通信系列二:mina入门总结

一.学习资料 Mina入门实例(一) http://www.cnblogs.com/juepei/p/3939119.html Mina入门教程(二)----Spring4 集成Mina http://www.cnblogs.com/juepei/p/3940396.html Apache Mina 入门实例--创建一个MINA时间服务http://loftor.com/archives/apache-mina-quick-start-guide.html MINA2.0用户手册中文版--系列文

mysql之show engine innodb status解读(转)

add by zhj: 我第一次知道这个命令是线上服务出了问题,然后同事用这个命令去查看死锁.但用这个命令看死锁有一定的局限性,它只能看到最后一次死锁, 而且只能看到死锁环中的两个事务所执行的最后一条语句(即被死锁卡住的那条语句),看不到整个死锁环,也看到不整个事务的语句.但是即使这亲,对我 们来说也非常有用,因为一般来说,数据库同时存在多个死锁环的可能性比较小,而且有了死锁环中的事务的最后一条语句,我们找到整个死锁环不是太难. "show engine innodb status"这

智慧中国杯百万大奖赛解读 | 学霸去哪了(二)

在上一篇中我们探讨了学生的消费数据,消费数据对本次竞赛预测来讲很重要.本篇将探索寝室门禁.图书借阅.图书馆门禁和学生成绩等一些和学生学习相关的数据,来看看学生的品行如何,虽然资助金和奖学金的性质不太一样,但我们毕竟还是想资助那些品学兼优的学生,而不是资助虽然家境很贫寒但不学无术的学生. 所以本篇探索的数据可以比较好的反应出这些情况.当然这里面还隐藏了更好玩的话题,学霸去哪了?话不多说,let's go! 一.数据目录概况 官方提供的数据分为两组,分别是训练集和测试集,每一组都包含大约1万名学生的

MINA快速传输文件

最近的项目使用MNA进行文件传输,只能传输到5~7MB/s:但是使用FTP等软件其实可以达到11MB/s,后来使用MINA原生传输,发现可以达到11MB/s,后来发现有以下两点可以需要注意优化: 1.直接用iobuffer传递,减少协议解析损耗: 2.fileaccess不要每次都创建: