双向注入
Dependency injection(依赖注入)和 inversion of control(控制反转)对于现在大多数的Java开发者来说那是再熟悉没有的了。依赖注入允许一个组件通过容器“注入”另一个组件到一个setter方法或者实例变量的方式,来获得被“注入”组件的引用(reference)。我们之前看过的所有依赖注入的实现,注入都是发生在组件创建的时候,而在此后实例的整个生命周期中不再改变。对无状态组件,这么做是有道理的。从客户端的角度来看,特定种类的无状态组件的所有实例都是可以替换的(实例池化)。另一方面,对于有状态的组件(Stateful session bean), 在用户的整个对话过程中,由于需要随时的保持用户的操作,其他Bean共享当前数据,此时传统的依赖注入不再是非常有效了。因此Seam引入了 bijection(双向注入) 这个名词,用来作为注入的广义概括。
和injection(单向注入)相比,bijection具有如下特点:
· contextual(上下文相关的) - 双向注入用来针对不同的上下文来组装有状态组件(你可以把Java实例任意的注入,任何有效的context: session, request, event等)
· bidirectional(双向的) - 被触发后,值从上下文变量中注射到组件属性中,也可以从组件属性outjected(反向注入) 回上下文,这样被调用的组件可以只通过改写自己的实例变量就同时操作了上下文变量的值
· dynamic(动态的) - 因为上下文变量的值随着时间不断改变,而且因为Seam组件是有状态的,双向注入在每次组件被调用的时候都发生。
概念是高深的,然而使用却是异常的简单:
// 从session context中,把monitor对象注入进来,同时调用结束后注入到event context中.
@In(scope=ScopeType.SESSION)
@Out(scope=ScopeType.EVENT)
Private Monitor monitor;
当然被Out出去的变量,不仅仅在java bean中可以访问,而且在任何需要的page中也同样的可以被EL表达式使用(如果它还没有被销毁的话):
<h:inputText value="#{monitor.name}" />
相比之下struts 的property标签却有点让人感觉莫名其妙,摸不着头脑。
组件式开发,提升效率
我们在谈论EJB的时候,往往只看到了EJB而忽略了它的定义。
Sun微系统公司有关Enterprise JavaBeans架构的定义如下:
Enterprise JavaBeans架构是一个用于开发和部署基于组件的分布式业务应用的组件架构。采用Enterprise JavaBeans架构编写的应用是可伸缩的、事务性的、多用户安全的。可以一次编写这些应用,然后部署于任何支持Enterprise JavaBeans规范的服务器平台上
说穿了,EJB其实就是一个运行在server端的组件。我觉得组件的概念,远远比EJB本身的意义大的多。
其实对于component模式,我觉得卖家具的比起java来,那是好得太多了,回家仔细看看吧,你的那一件家具,不是一块板,一颗钉,拼装起来的?理想状态下,我们只需要在action bean中从组件的实例池中,取出一个个的组件来,拼装一下他们的结果就可以了。如此,还需要考虑什么耦合,什么重用么?
那么我们怎么才能有效的进行组件式开发呢?其实也很简单,只需要使用注解声明一下就可以了,如下例:
// 定义一个EJB组件,用@AutoCreate声明该组件在被调用时,自动创建
@Name("editMonitorBean")
@Stateless
@AutoCreate
public class EditMonitorBean extends StatelessHome implements EditMonitor {
@Begin(join = true)
public Monitor showMonitor() {
Monitor monitor = em.find(Monitor.class, monitorId);
List<Component> componentList = em.createQuery(
"select c from Component c " + " where c.monitor = :monitor "
+ " order by c.catalogName, c.modifiedDate desc").setParameter("monitor", monitor)
.getResultList();
return monitor;
}
}
// 在action listener中使用@In调用EJB组件
@Name("editMonitorAction")
@Scope(ScopeType.CONVERSATION)
public class EditMonitorAction extends ActionHome {
@In
private EditMonitor editMonitorBean;
private List<Monitor> monitorList;
public void showMonitor() {
monitor = editMonitorBean.showMonitor();
monitorHistoryPaging = editMonitorBean.findMonitorHistory(monitor);
}
}
而seam之妙却不止于此,充其量EJB只不过是server端的组件,但seam与richfaces或icefaces等第三方jsf组件库的完美结合,却使之同时兼具客户端和server端两者之长,真是令人其欣喜为何如!试想一下,一堆堆美妙的组件摆在你的面前供你挑选,把你的页面装扮的就如同windows应用一样美妙,你还能不高兴得跳起来?
或许你尚有疑虑20%的数据从何而来。当然,这个无法进行精确的统计,但让我们试想一下,当你全部的开发工作,只是从组件库中,根据自己的业务逻辑,取出合适的组件,然后从容的拼装到一起的时候,在计算上大量的测试时间,我想20%也有些保守了。
一乱一治,这些年来java带给web开发人员的苦痛,远远大于欣喜。我们渴望着一个能够领袖群雄的王者早日归来,尽速结束这种兵戈纷攘,狼烟蔽日的无聊局面。带领着Java,带领着我们这些草民走出山重水复的困顿,再现那柳暗花明的世外桃源。
参考资料:
1. 《Enterprise JavaBeans 3.0中文版(第5版)》 - 电子工业出版社 / Bill Burke JBoss公司的首席架构师
2. Seam Home
3. 《Web开发之华山论剑—Web表现层跑完龙套唱主角》 - 《程序员》2006年第10期
4. JBoss Seam 2.0.0.GA Chinese (beta) – 满江红小组翻译
5. Cognos Audit Monitor
6. 《印光大师文抄》