AOM 2.0的神奇魔力之五:LiteBean

阅读更多

AOM 2.0的神奇魔力之五:LiteBean

Kevin

1. 前言
2. 什么是LiteBean
3. LiteBean的声明
4. LiteBean的生命周期
5. LiteBean与页面的对应关系
6. 资源注入
7. 可扩展的资源注入:一种思路
8. 总结

1.前言

本教程介绍 AOM 2.0中的LiteBean,在阅读本文之前,我建议你首先阅读前几篇文章:

AOM 2.0的神奇魔力之一:约定优于配置

AOM 2.0的神奇魔力之二:国际化

AOM 2.0的神奇魔力之三:输入校验

AOM 2.0的神奇魔力之四:模型事件

2.什么是LiteBean

LiteBean,脱胎于JSF规范中的 Managed Bean,在 AOM 2.0中,对 Managed Bean 做了大量的扩充,最终演化成了目前的 LiteBean。LiteBean 是 AOM 中非常重要的一个概念,它即是展现层与业务层之间的粘接器,同时也是 AOM 与其它成熟编程模型的粘接器,如 Spring、EJB 3 等。

事实上,在我们前面几篇文章中,已经大量涉及到 LiteBean 相关内容,但我们从来没有系统化的介绍过 LiteBean,本文,将对各位读者整体的介绍一下 LiteBean 相关内容。

另外需要注意的是:@ManagedBean 的 annotation 将逐渐被 @LiteBean 代替,但为了保持兼容性,本文将继续延用 @ManagedBean 这个 annotation。

3.LiteBean的声明

LiteBean的声明在AOM中是非常简单的一件事情,只需要一个 @ManagedBean 的 annotation 声明即可。一个比较完整的LiteBean声明如下:

@ManagedBean(name="LiteBean", scope=ManagedBeanScope.NONE, description="The description", displayName="your_display_name")
public class LiteBean {

}

其中,如果不指定name,那么,默认以类名称(不含包名)作为name,scope的默认值为none,description及displayName基本上都可以忽略。

所以,一个更简单的LiteBean的声明是:

@ManagedBean
public class LiteBean {

}

由于LiteBean是被容器自动创建的,因此,很自然的,LiteBean必须要有个无参数的构造函数。有的同学要问了:“有时候通过无参数的构造器进行 LiteBean 的创建方式不能够完全满足我的要求, 因为在某些场景下,我需要知道一些上下文,才能够正确的创建并初始化一个LiteBean,这种情况如何解决?” 这种情况下,你可以通过Factory模式来创建LiteBean,如下所示:

@ManagedBean(scope=ManagedBeanScope.APPLICATION)
public class UserFactory {
@Factory(name="user", scope=ManagedBeanScope.SESSION)
public User createUser() {
return new User();
}
}

请注意,这个Factory本身也必须要是个LiteBean。

LiteBean被声明以后,就能够被EL表达式所引用了,但如果你要访问LiteBean的属性,那么,你还要为该属性准备 getter/setter 方法。笔者并不认为 getter/setter 方法存在什么问题,但事实上,某些场景下,getter/setter 方法过多,确实会影响到开发者的注意力,因此,AOM中又引入了一个 @ManagedProperty 的 annotation,如果在一个属性上进行@ManagedProperty的标注,那么,这个属性就成为“Managed Property”,并可以被EL表达式引用,如:

@ManagedBean
public class LiteBean {

@ManagedProperty
private String name;
}

此时,你可以通过#{LiteBean.name}引用这个变量。但 @ManagedProperty 的作用并不仅限于此,你还可以在该声明中指定一个EL表达式,该EL表达式的值,将作为该属性的初始化值,如:

@ManagedBean
public class LiteBean {

@ManagedProperty("#{OtherLiteBean.someProperty}")
private String name;
}

基本上,我们从来不需要再维护faces-config.xml,但我们也不排斥通过 faces-config.xml 来进行 ManagedBean/ManagedProperty的声明。

此外需要提醒读者注意的是,如果在@ManagedProperty中通过EL表达式引入别的 LiteBean,需要注意 LiteBean的生命周期,下面就让我们来介绍一下什么是 LiteBean的生命周期。

4.LiteBean的生命周期

写过jsp程序的同学都了解在jsp页面中,有几个默认隐含对象,如:request、session、application等,我们经常会把一些信息存放到这些对象域中,其中又以 session 对象使用的最为频繁。同样的,一个 LiteBean 被创建以后,也会被放到这些不同的生命周期域里,分别是:

request:指从请求开始至请求结束期间。

session:指用户的会话过程期间。

application:指应用的整个生命周期。

简单来说:当一个应用启动时,AOM会扫描该应用中的所有类,从中找出所有的 LiteBean(会记住它的name及其对应的具体Java类),当在需要引用某一个LiteBean时,它会从 request、session、application域中依次查找是否已经存在该LiteBean,如果不存在,那就创建它并将其放入到指定的生命周期域里。

此外,LiteBean还有一个名称为none的生命周期范围,意思就是说:此LiteBean每次都创建新的实例,用完就丢掉。

由此,我们也明白了另外一个逻辑:如果一个 LiteBean 引用了另外一个 LiteBean,那么,被引用的LiteBean的生命周期,一定要长于或等于引用的这个LiteBean。

Table1.合法的LiteBean引用

引用的LiteBean的生命周期 被引用的LiteBean的生命周期
none none
application none, application
session none, application, session
reqeust none, application, session, request

5.LiteBean与页面的对应关系

LiteBean可以被页面中的EL表达式所使用,但基于 IoVC 思想,我们是竭力避免在页面中出现 EL 表达式的,那么这就引来一个问题:一个页面,到底是如何跟某个或者某几个LiteBean关联起来的呢?

你可以认为是通过配置文件关联起来的,你也可以认为是基于“约定优于配置”这一原则而约定成俗的。而实际情况是: 你即可以通过配置文件指定,也可以采用约定规则,包括这种约定能力的自身也是配置出来 的。

这个配置文件就是在 AOM 2.0中引入的 operamasks.xml,位于web应用的 WEB-INF目录下。事实上,这个文件默认都会包含如下内容,并且,我们也强烈推荐你加上此段内容:



*
#{~View}Bean

上述配置,实际上就是配置了一种约定能力,解释如下:如果页面的文件名是 abc.xhtml(扩展名不定,也可以是abc.jsp),那么,所对应的 LiteBean 的名称是 AbcBean。甚至你的文件名称可以是a-b-c.xhtml,对应的 LiteBean的名称依然是 AbcBean(请注意是LiteBean的name,而不是 java类的名称)。如果你希望LiteBean name的首字母小写,那就将配置文件改成:

#{~view}Bean

那么,abc.xhtml,对应的LiteBean就是:abcBean。

如果应用变得复杂,文件要分目录存放,那么,建议你再做如下配置:


/gl/*
gl.#{@View}Bean

上述配置意思就是:凡位于gl目录下的页面,其对应的 LiteBean的名称就有前缀 gl,譬如 /gl/abc.xhtml 对应的 LiteBean 的 name 就是:gl.AbcBean;gl/test/def.xhtml 对应的 LiteBean 的 name 则是:gl.test.DefBean。

当然,如果你要单独指定某个页面所对应的LiteBean,那就这样:


/user/login.xhtml
LoginBean
RegisterBean
UserListBean

在上述情况下,login.xhtml会对应LoginBean、RegisterBean、UserListBean这三个LiteBean。

事实上,如果你用 Apusic Studio 来进行开发工作的话,这个文件(operamasks.xml)你根本不需要关心,由 Apusic Studio自动帮你维护。

再次强调:针对页面和对应的 LiteBean ,我们强烈建议您采用“约定优于配置”这一原则,而在 AOM 中,这种约定的能力也是配置出来的。

6.资源注入

时至今日,Inversion of Control,Dependency Injection,等概念已经耳熟能详;Spring等IoC容器也大行其道;甚至于很多同学并没有真正理解到底什么是IoC以及它带给我们的意义, 但一个个的Spring用得倍熟。究其原因,是因为 Spring 为我们提供了许多便利,尤其是对象的创建与销毁。AOM同样如此,你所需要的任何资源,只需要通过一个 @Inject 即可注入。在 AOM 中,你可以注入以下资源:

java.util.logging.Logger
javax.faces.context.FacesContext
javax.faces.context.ExternalContext
javax.faces.application.Application
javax.faces.application.NavigationHandler

javax.el.ExpressionFactory
org.operamasks.faces.event.EventBroadcaster
org.apache.commons.logging.Log

举个简单的例子,如果你要使用 java.util.logging.Logger对象,那么,你只需要:

@Inject
private Logger logger

AOM会根据对象类型自然判断出你需要注入的资源是什么。上例中,由于Logger是 java.util.longg.Logger,因此,AOM会自动初始化 logger对象,然后你就可以拿着 logger 对象直接用了。

此外,你还可以在@Inject中指定EL表达式,AOM会对该EL表达式求值,并将结果赋值给该属性,如:

@ManagedBean(name="testBean", scope=ManagedBeanScope.SESSION)
public class TestBean {

@Inject("#{LiteBean.name}")
private String name;

}

如果你希望上述属性能够被EL表达式所访问,那么,你就再加一个 @Accessible 的声明:

@ManagedBean
public class TestBean {

@Inject("#{LiteBean.name}")
@Accessible
private String name;

}

这样,别人就可以通过#{TestBean.name}访问该属性了。

同时,AOM也支持JavaEE 5.0中规定的跟资源注入相关的 Annotation,如:

@Resource
@Resources
@EJB
@EJBs
@WebServiceRef
@WebServiceRefs
@PersistenceContext
@PersistenceContexts
@PersistenceUnit
@PersistenceUnits

假设我要注入一个数据源,那么,你可以这样:

@Resource(mappedName="jdbc/MyDataSource")
DataSource ds;

7.可扩展的资源注入:一种思路

有同学要问了:这种资源注入的方式很好用啊,我能否将其扩展,让我的开发团队使用这种便捷的方式来注入自己的对象呢?譬如说, 我现在有一些自己的对象,这些对象都有自己的名字,我能否很方便的通过名字来注入相应的对象呢?

自然没问题,AOM是开放的,其架构的灵活性,也足以支撑这种扩展,譬如,你可以实现一个自己的ELResolver,然后通过 ApplicationListener注册到AOM。本文中,笔者不想介绍这么复杂的内容,只是通过一种简单的模式来解决此问题,示例性代码如下:

@ManagedBean
public class MyBeanFactory {

public Object get(String name) {
if("someKey".equals(name)) {
return new MyBean1();
}
else if ("otherKey".equals(name)) {
return new MyBean2();
}
return new MyBean3();
}
}

如果要注入相关资源,可以这样:

@Inject("#{MyBeanFactory.get('someKey')}")
private MyBean1 bean1;

@Inject("#{MyBeanFactory.get('otherKey')}")
private MyBean2 bean2;

8.总结

LiteBean是AOM中非常重要的一个概念,它即是展现层与业务层的粘接器,同时也是 AOM 与其它编程模型(如Spring、EJB 3等)的粘接器。在下文中,我们将介绍 AOM 是怎样与 Spring 紧密集成的。

你可能感兴趣的:(Bean,Spring,XHTML,编程,EJB)