JBoss Seam的事件机制 (2)

JBoss Seam如何做到松耦合的架构呢?光有具备上下文的组件模型是不够的。还必须有:

事件模型。事件模型通过事件<-->监听器模式来构建。采用的方式是象JSF方法绑定一样的方式实现。
使用注释和拦截器来纵向切入实现业务逻辑的组件,从而达到松耦合的事件触发和响应
JBoss Seam的组件模型本身就是为事件驱动的应用来设计的。这些事件都是通过JSF的表达式语言的方法绑定来映射的。在JBoss Seam中,事件可以分为:

JSF事件,例如:<h:commandButton value="Click me!" action="#{helloWorld.sayHello}"/> JSF的按钮绑定动作

jBPM状态转移事件,例如:<start-page name="hello" view-id="/hello.jsp"> <transition to="hello"> <action expression="#{helloWorld.sayHello}"/> </transition></start-page> jBPM流程或页面流定义

Seam页面动作,页面事件发生在我们渲染一个页面之前,我们通过在WEB-INF/pages.xml文件中配置页面动作。我们可以为一个特定的JSF视图ID (View ID)设定一个页面动作,例如:<pages> <page view-id="/hello/hello.jsp" action="#{helloWorld.sayHello1}"/></pages>
我们也可以使用通配符为一个页面模式设定页面动作,例如:
<pages> <page view-id="/hello/*" action="#{helloWorld.sayHello2}"/></pages>
如果多个页面动作匹配当前的页面视图的话,那么所有动作按照最窄到最宽泛的顺序依次调用
例如上述sayHello1,sayHello2动作都和hello.jsp匹配,那么在hello.jsp页面上先调用
sayHello1然后调用sayHello2。页面动作可以返回一个JSF的输出outcome,如果outcome
不为null的话,Seam将使用定义好的规则去导向到一个视图。更棒的是page元素中的视图
view-id可以不是JSP页面或者Facelet页面,允许我们通过view-id来整合基于动作的Struts
或者Webwork框架。你可以使用action元素指定多个条件页面动作(在某种条件下才执行的动作)
例如:
<pages> <page view-id="/hello.jsp"> <action execute="#{helloWorld.sayHello}" if="#{not validation.failed}"/> <action execute="#{hitCount.increment}"/> </page></pages>


Seam组件驱动的事件,Seam组件之间可以直接通过方法调用来相互沟通。有状态的组件可以实现观察者模式。虽然如此,Seam提供的组件驱动的事件比直接通过方法调用更加松耦合。我们来看一下如何设置组件驱动的事件。我们可以在components.xml文件中设置事件监听器(观察者):<components> <event type="hello"> // 设置事件, Observable <action execute="#{helloListener.sayHelloBack}"/> // 设置监听器,Observer <action execute="#{logger.logHello}"/> // 设置监听器,Observer </event></components> 你可能想问事件类型type="hello"是什么,它只是一个任意的字串。事件类型将在组件驱动事件的时候使用
(raiseEvent)。当事件发生时,在事件中注册的动作将根据在components.xml文件中的次序依次调用。你可能要问:我如何
在组件中触发一个事件呢?基本上,你有两种选择:使用内置的组件和通过注释。下列代码在运行HelloWord的sayHello方法时
触发事件类型为"hello"的事件(在components.xml文件中配置):
@Name("helloWorld")public class HelloWorld { public void sayHello() { FacesMessages.instance().add("Hello World!"); Events.instance().raiseEvent("hello"); // Events 内置组件 触发hello事件 }}
@Name("helloWorld")public class HelloWorld { @RaiseEvent("hello") // 注释 触发hello事件 public void sayHello() { FacesMessages.instance().add("Hello World!"); }}
我们看到HelloWorld的sayHello方法其实是事件的产生者。值得注意的是事件的产生者和事件的消费者
(监听者)没有任何依赖性,例如下面的hello监听器和上述的HelloWord没有依赖:
@Name("helloListener") // 在components.xml文件的hello事件中注册的监听者public class HelloListener { public void sayHelloBack() { // 当hello事件触发后,监听者调用该监听方法 FacesMessages.instance().add("Hello to you too!"); }}
注意:如果你讨厌在components.xml文件配置太多事件和监听器,那么你也可以使用注释来配置:
@Name("helloListener")public class HelloListener { @Observer("hello") // 指明使用sayHelloBack方法来监听hello事件 public void sayHelloBack() { FacesMessages.instance().add("Hello to you too!"); }}
到这里你会发现我们根本没有用事件对象!实际上,事件产生者和事件消费者之间根本不必有事件对象来
处理状态的问题。状态问题由Seam的上下文处理了,并且在Seam组件之间共享!
不过,你要真的想要一个事件对象,可以象这样:
@Name("helloWorld") // 事件产生者public class HelloWorld { private String name; public void sayHello() { FacesMessages.instance().add("Hello World, my name is #0.", name); Events.instance().raiseEvent("hello", name); // name是String参数,传递多个Object参数 }}
@Name("helloListener") // 事件监听者public class HelloListener { @Observer("hello") public void sayHelloBack(String name) { FacesMessages.instance().add("Hello #0!", name); }}

Seam具有上下文的事件,Seam本身定义了一系列内置的事件。注意这些事件的名称都是字符串定义的:
Seam组件可以监听(观察)这些事件,就像他们观察组件驱动的事件一样。我们将在别的文章中专门讲述。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值