apache mina 学习(十二)-----状态机(stateMachine)

原创 2012年03月21日 15:06:15

mina状态机的工作原理:

mina中引入了StateContext对象,顾名思义是一个状态上下文对象,用来保存当前的状态,当代理state对象的方法被调用的时候,这个上下文对象会通知stateContextLookup的实例去从方法参数中获取stateContext,通常情况下StateContextLookup 的实现类会循环方法的参数进行查找,并创建指定的对象,并从这个对象中得到一个上下文对象,如果没定义上下文对象,StateContextLookup 会创建一个新的并存放到对象中。

当代理mina的IoHandler时,我们将用IoSessionStateContextLookup实例来查找Iosession中的参数,然后用IoSession的属性来为每一个Session存储一个StateContext对象。这样同样的状态机可以让每个mina的session使用,而不会彼此影响。

我们使用StateMachineProxyBuilder创建一个代理时,我们一直没有我们一直没有配置StateContextLookup 使用哪种实现。如果没有配置,系统会使用SingletonStateContextLookup 。SingletonStateContextLookup 总是不理会方法中传递给它的参数,它一直返回一个相同的状态上下文。很明显,这中方式在多个客户端
并发的情况下使用同一个同一个状态机是没有意义的。

请努力看懂下面的例子:这个事件Event {id = "messageReceived", arguments = [ArrayList a = [...], Integer b = 1024]}下面的方法将和这个事件是等价的:

// All method arguments matches all event arguments directly
@Transition(on = "messageReceived")
public void messageReceived(ArrayList l, Integer i) { ... }

// Matches since ((a instanceof List && b instanceof Number) == true)
@Transition(on = "messageReceived")
public void messageReceived(List l, Number n) { ... }

// Matches since ((b instanceof Number) == true)
@Transition(on = "messageReceived")
public void messageReceived(Number n) { ... }

// Methods with no arguments always matches
@Transition(on = "messageReceived")
public void messageReceived() { ... }

// Methods only interested in the current Event or StateContext always matches
@Transition(on = "messageReceived")
public void messageReceived(StateContext context) { ... }

// Matches since ((a instanceof Collection) == true)
@Transition(on = "messageReceived")
public void messageReceived(Event event, Collection c) { ... }

但是下面的方法不会和这个事件相匹配:

// Incorrect ordering
@Transition(on = "messageReceived")
public void messageReceived(Integer i, List l) { ... }

// ((a instanceof LinkedList) == false)
@Transition(on = "messageReceived")
public void messageReceived(LinkedList l, Number n) { ... }

// Event must be first argument
@Transition(on = "messageReceived")
public void messageReceived(ArrayList l, Event event) { ... }

// StateContext must be second argument if Event is used
@Transition(on = "messageReceived")
public void messageReceived(Event event, ArrayList l, StateContext context) { ... }

// Event must come before StateContext
@Transition(on = "messageReceived")
public void messageReceived(StateContext context, Event event) { ... }

状态继承:

StateMachine.handle(Event)方法如果不能找到一个transaction和当前的事件在当前的状态中匹配的话就是去找他得父状态,依次类推,知道找到为止,所以我们有时候很需要状态的继承:

@State    public static final String A = "A";
@State(A) public static final String B = "A->B";
@State(A) public static final String C = "A->C";
@State(B) public static final String D = "A->B->D";
@State(C) public static final String E = "A->C->E";
运行:

public static void main(String[] args) {
    ...
    deck.load("The Knife - Silent Shout");
    deck.play();
    deck.pause();
    deck.play();
    deck.stop();
    deck.eject();
    deck.play();
}
可能会保以下的错误,至少我第一次是报错的:

...
Tape stopped
Tape ejected
Exception in thread "main" o.a.m.sm.event.UnhandledEventException: 
Unhandled event: org.apache.mina.statemachine.event.Event@15eb0a9[id=play,...]
    at org.apache.mina.statemachine.StateMachine.handle(StateMachine.java:285)
    at org.apache.mina.statemachine.StateMachine.processEvents(StateMachine.java:142)
这个异常我们无法处理,所以我们将添加一个指定的事务来处理所有不能匹配的事件:

@Transitions({
    @Transition(on = "*", in = EMPTY, weight = 100),
    @Transition(on = "*", in = LOADED, weight = 100),
    @Transition(on = "*", in = PLAYING, weight = 100),
    @Transition(on = "*", in = PAUSED, weight = 100)
})
public void error(Event event) {
    System.out.println("Cannot '" + event.getId() + "' at this time");
}
运行:

Tape stopped
Tape ejected
Cannot 'play' at this time.
当然,定义所有状态的root更有效:

public static class TapeDeckHandler {
    @State public static final String ROOT = "Root";
    @State(ROOT) public static final String EMPTY = "Empty";
    @State(ROOT) public static final String LOADED = "Loaded";
    @State(ROOT) public static final String PLAYING = "Playing";
    @State(ROOT) public static final String PAUSED = "Paused";
    
    ...
    
    @Transition(on = "*", in = ROOT)
    public void error(Event event) {
        System.out.println("Cannot '" + event.getId() + "' at this time");
    }
}




使用Spring StateMachine框架实现状态机

spring statemachine刚出来不久,但是对于一些企业的大型应用的使用还是十分有借鉴意义的。 最近使用了下这个,感觉还是挺好的。 下面举个例子来说下吧:    创建一个Sprin...

使用Spring StateMachine框架实现状态机

使用Spring StateMachine框架实现状态机  2016-12-18  Spring Boot 被围观 1423 次 Spring StateMachine...

apache mina 学习(十一)-----状态机(stateMachine)

当我们在开发复杂的网络应用的时候往往需要一个状态的设计,下面就以官网的一个收录机播放为例来说明: 收录机状态之间的转换我们应该不难理解:首先是空状态,就是什么磁带就没放进去然后是有磁带的状态,这两个...
  • Cages
  • Cages
  • 2012年03月21日 09:28
  • 3134

Mina状态机StateMachine

首先,关于状态机的一个极度确切的描述是它是一个有向图形,由一组节点和一组相应的转移函数组成。状态机通过响应一系列事件而“运行”。每个事件都在属于“当前” 节点的转移函数的控制范围内,其中函数的范围是节...
  • canlets
  • canlets
  • 2013年11月06日 18:53
  • 1209

Mina状态机StateMachine()

接下来我们要把这样的方式用在通信中。用通信的方式来模拟录放机的按钮。 我们先看状态的定义:...
  • canlets
  • canlets
  • 2013年11月06日 19:59
  • 1904

Mina状态机介绍(Introduction to mina-statemachine)

如果你使用Mina开发一个复杂的网络应用时,你可能在某些地方会遇到那个古老而又好用的状态模式,来使用这个模式解决你的复杂应用。然而,在你做这个决定之前,你或许想检出Mina的状态机的代码,它会根据当前...
  • whycold
  • whycold
  • 2011年01月19日 23:51
  • 2682

apache mina 学习(十三)-----状态机和IoHander配合使用

现在我们把上一张的收录机的例子改造为一个tcp服务器,用文本的传输,效果如下; telnet localhost 12345 S: + Greetings from your tape deck! ...
  • Cages
  • Cages
  • 2012年03月21日 15:36
  • 2913

《Apache MINA 2.0 用户指南》第十四章:状态机

本章对 MINA 框架中最复杂的一个主题 - 状态机进行了深入分析和讨论。内容包括状态机小例子、状态机的工作原理、注解匹配、状态继承、错误处理等等主题和内容,全文穿插大量示例代码,避免我们深陷于复杂的...
  • defonds
  • defonds
  • 2014年01月14日 17:37
  • 3756

Apache mina2 用户指南(十四)状态机

如果你在使用 MINA 开发一个具有复杂网络的交互的应用,在某种情况下你可能会发现你自己试着使用经典的 状态模式 以尝试解决其复杂性。但是,在你那么干之前,你可能想要检出 mina-statema...

使用Spring StateMachine框架实现状态机

Spring StateMachine框架可能对于大部分使用Spring的开发者来说还比较生僻,该框架目前差不多也才刚满一岁多。它的主要功能是帮助开发者简化状态机的开发过程,让状态机结构更加层次化。前...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:apache mina 学习(十二)-----状态机(stateMachine)
举报原因:
原因补充:

(最多只允许输入30个字)