我们知道,标准的JSF提供了通过faces-config.xml配置文件来定义ManagedBean同时进行ManagedProperty注入的方案。例如,以下配置定义了两个ManagedBean:personBean和communityBean,并对communityBean的name属性进行了初始化与对leader属性进行了依赖注入:
<managed-bean>
<managed-bean-name>personBean</managed-bean-name>
<managed-bean-class>test.PersonBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>communityBean</managed-bean-name>
<managed-bean-class>test.CommunityBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>name</property-name>
<property-class>java.lang.String</例如配置property-class>
<value>Operamasks</value>
</managed-property>
<managed-property>
<property-name>leader</property-name>
<property-class>test.PersonBean</property-class>
<value>#{personBean}</value>
</managed-property>
</managed-bean>为了减轻编程工作量,OperaMasks提供了注解@ManagedProperty来进行同样功能的依赖注入。例如,在OperaMasks中可以用以下代码直接注入personBean或aSpringBean或者它们的一个属性值:
@ManagedBean(name="communityBean", scope=ManagedBeanScope.SESSION)
public class Test2Bean implements Serializable {
//注入另一个LiteBean
@ManagedProperty(value = "#{personBean}")
private PersonBean leader;
//注入另一个LiteBean的一个属性
@ManagedProperty(value = "#{personBean.name}")
private String leaderName;
//注入一个Spring bean,aSpringBean是Spring配置文件中定义的bean的id值
@ManagedProperty(value = "#{aSpringBean}")
private IPersonSpringService personService;
通过注解进行注入与通过配置文件注入两种方式可以结合起来使用,遵循以下规则:
1. 若注解与配置文件定义了同名的ManagedBean,则两个定义均会生效,作用于同一个Bean。若配置中存在冲突,以配置文件为准。例如在上面的例子中,如果删去配置文件中关于leader属性的注入描述,那么就会使用注解所定义的注入规则。同时配置文件中对name属性的初始化配置仍然生效。
2. 分别使用注解与配置文件定义ManagedBean可互相引用。例如在上面例子中,如果在配置文件中删去对personBean的定义,改为在PersonBean类上使用注解进行定义,在配置文件中communityBean仍然可以对其进行注入。
既然@ManagedProperty注解是标准JSF注入的一种简写形式,那么注入的发生时机与标准JSF的ManagedBean生命周期是一致的,也就是说,注入动作发生在ManagedBean创建之后(构造方法执行之后)。当ManagedBean中所有ManagedProperty注入完成后,容器将调用@PostConstruct注解的生命周期回调方法。
可以看出,@ManagedProperty注解所定义的注入是与ManagedBean自身的生命周期相关的。OperaMasks中同时还提供了另一种与JSF请求处理生命周期相关的注入动作,通过@Inject注解进行定义。与@ManagedProperty类似,使用@Inject注解也可以用来注入另一个ManagedBean或Spring bean或它们的一个属性值。
@ManagedBean(name="communityBean", scope=ManagedBeanScope.SESSION)
public class CommunityBean implements Serializable {
//注入另一个LiteBean
@Inject(value = "#{personBean}")
private PersonBean leader;
//注入另一个LiteBean的一个属性
@Inject(value = "#{personBean.name}")
private String leaderName;
//注入一个Spring bean,aSpringBean是Spring配置文件中定义的bean的id值
@Inject(value = "#{aSpringBean}")
private IPersonSpringService personService;与@ManagedBean相比,使用@Inject进行注入具有这些特点:
1. @Inject注入依赖于IoVC绑定机制,因此请求处理生命周期中在IoVC绑定之前的阶段,主要是恢复视图阶段的生命周期侦听方法中,ManagedBean的构造方法与@PostConstruct方法中无法使用被注入的值(此时实际取值不可确定,详见第 20.2 节 “IoVC的时机”);
2. @Inject注解提供了order属性,可以决定属性注入的顺序;
3. @Inject注解提供了renew属性,可以确定在每次请求处理生命周期是否对属性进行重新注入。我们知道,使用@ManagedProperty时,不应该把作用范围较小的ManagedBean注入到作用范围较大的ManagedBean中(例如把scope=request的ManagedBean注入到scope=session的ManagedBean中)。原因是在作用范围较大的ManagedBean的生命周期中,引擎会多次废弃作用范围较小的ManagedBean的旧实例并重新创建新实例。但由于注入动作只在范围较大ManagedBean创建时发生一次,导致它将一直持有最初的被注入实例,而没有随着引擎一起更新。使用@Inject标签进行注入时,可以将@Inject注解的renew属性设为true,通知OperaMasks引擎在每轮请求处理生命周期中重新进行注入,从而允许将小范围的ManagedBean注入到大范围的ManagedBean中。
4. 除非设置了renew=true,否则@Inject只对初值为null的属性进行注入。若在注入时属性已被初始化,则不进行注入。
5. 原则上@Inject注解主要用于向对象类型的属性进行依赖注入,而不应该用于基础类型(例如int等)。@Inject注解指定的初值(value属性)如果不是EL表达式,将被自动加上EL表达式标识。例如上面例子中的"personBean"将会被转换为"#{personBean}进行处理。
6. @Inject注解可以用来注入以下系统资源:
java.util.logging.Logger javax.faces.context.FacesContext javax.faces.application.Application javax.faces.application.NavigationHandler javax.el.ExpressionFactory org.operamasks.faces.event.EventBroadcaster
OperaMasks中还加入了一个与注入和初始化有关的注解@Init。这个注解作用在ManagedBean的方法上,通过注解的value属性或方法签名(init开头后续首字大写的属性名)指定一个Bean属性,当这个属性进行IoVC绑定之前,如果属性值为null,引擎会回调被注解的方法。例如:
@Bind(id="name")
private String name;
//通过命名规则指定属性
@Init
public void initName() {
System.out.println("init name called");
name = "OperMasks";
}
@Bind
private String gender = "male";
//由于属性已有初值,此方法不会被调用
@Init
public void initGender() {
System.out.println("init gender called");
gender = "female";
}
@Inject(value = "#{personBean}")
private PersonBean leader;
//通过注解的value属性指定属性
@Init("leader")
public void LeaderInit() {
System.out.println("init leader called");
}
//由于没有此属性,此方法不会被引擎回调
@Init
pubilc initNoSuchField() {
System.out.println("init for nothing");
}这个注解的主要作用是在绑定之前对属性值进行初始化。
注意由于@Inject注入动作也作为IoVC绑定处理,因此也会触发对应的@Init方法,此时属性值还未被注入,对于renew为false的@Inject注入,如果在对应@Init方法中将待注入属性的初值设为非空值,则不会发生后续注入动作。而对于renew为true的@Inject注入,对应的@Init方法将不被执行。