web beans --weld---JSR-299 快速入门
本人使用JSF2.0/webbeans(WELD)开发的例子:http://download.csdn.net/source/2336819
前沿:全球第一篇中文webbeans(weld)整理资料...原装处女作..
2009年12月,sun发布了javaEE6.这个消息如同梦中情人的一个滚烫的吻,吻醒了我久久期盼的心情...抓紧研究,在百忙之中,写下此快速入门,由于接触时间不长,如有疏漏或者错误之处,敬请各位多多指教...
引言:webeans就是JSR-299,在发布之时,改成学名(weld),不过你还能看到CDI(上下文依赖注入)的影子,无论啥名字,它还是一个玩意.webbeans的思想源于seam,但是webbeans1.0比seam更加简介易用.
1.
@Initializer注释,表示当bean被实例化后立即执行的方法.类似于seam中的@create.通过此注释的构造方法或者其他业务方法的参数均是可注入的。
2.
Webbean的生命周期是有生命周期管理器管理,保证不同的上下文中的bean实例不同,相同上下文中的实例只共享一个.这种有状态特性,状态的WebBean可以像服务一样使用!客户端不需要关注本身以及它使用的WebBean的生命周期,甚至它根本不需要知道生命周期是什么。WebBean通过传递消息来交互,WebBean的实现定义了他们自己状态的生命周期。
3.@Named注释 一个webbean上下文名称.可以通过名称在页面(JSP/JSF)直接被引用.
4.
Web Bean 规范声称一个具体的Java类可以成为一个简单的Web Bean, 只要这个类:
1)它不是一个EE容器管理的组件,例如一个EJB,一个Servlet或者一个JPA实体,
2)它不是一个非静态的静态内嵌类,
3) 它不是一个参数化类型,并且它拥有一个无参构造器,或者构造器具有@Initializer注释。这样,几乎所有的JavaBean都可以是一个简单的Web Bean。每个被简单Web Bean直接或者间接实现的接口都是这个简单Web Bean的一个API类型。这个类和它的超类也是API类型。规范指出所有EJB3类型的会话Bean或者单例Bean都是企业级Web Bean。消息驱动Bean不是Web Beans因为它们不能被注入到其他对象中;但是它们可以使用大部分Web Bean的功能,包括依赖注入和拦截器。
我们什么时候使用企业级WebBean来替代简单WebBean呢?当我们需要EJB提供的高级的企业服务的时候,例如:
•方法水平的事务管理和安全,
•并发管理
•实例水平的有状态会话Bean的钝化和无状态会话Bean的实例池,
•远程或者Web服务调用,和
•定时器以及异步方法,
在这中情况下,我们应该使用一个企业级Web Bean。当我们不需要这些服务的时候,一个简单Web Bean就足够了。5.
@Login User user;
这句话中@Default是绑定类型,User是API类型,对于webbeans而言,管理器对绑定类型使用生命周期拦截控制,并给任何的通过绑定类型的引用的webbean,设定为注入点,即默认注入.如果被注入的对象未被实例化,将会执行标注为此绑定类型的生产方法.
…
@produced @Login User getCurrentUser(){…..}绑定类型是可以自定义的,定义方式和普通注释声明的借口方法一致..
6.
Web Beans支持三种主要的依赖注入机制 :1)构造器参数注入:
public class Shop{ private Item item; @Initializer Public Shop(@Default Item item){ This.item = item; } }
构造参数注入,并没有使用webbeans的注入特性,和POJO一样. 使用了bean生命周期管理方式@Initializer.
2) 初始化 方法参数注入:
public class Shop{ private Item item; @Initializer Public void setItem(@Default Item item){ This.item = item; } }
无webbeans的注入特性,和POJO类似,使用了bean生命周期管理方式@Initializer.
3) 和直接的域注入:
@DefaultItemitem;
使用了webbeans的注入特性.但是需要注入的对象必须有绑定类型(如:@current),具有绑定类型的对象,同时就是注入点.
注入顺序:
a)WebBean管理器调用WebBean构造器来获得一个WebBean的实例。构造方法需标注@Initializer.因为规范要求webbeans不能有构造函数.
b)WebBean管理器初始化这个Webbean的所有注入域的值。需绑定类型标注(如:@Default).
c)WebBean管理器调用这个WebBean的初始化方法。@Initializer标注的方法.
d)如果有 @PostConstruct 方法的话,调用这个方法。e)生产者方法也支持参数注入:@produces @Shop createShop(@Default Item item){…},生产者方法在运行时绑定类型(如@shop)的类未被实例化调用.
7.
Webbeans支持绑定类型组合注释 ,如@User @Manager User user;只有同时具有两种绑定类型的类才会被注入,这个很好理解,就像接口的概念一样.其生产方法如下:
@produces @User @Manager User createManager(){….}
8.
默认的绑定类型@Default:
WebBeans定义了一个@Default绑定类型,这个绑定类型是任何注入点或者没有显式指定绑定类型的WebBean的默认绑定类型。
通常有两种环境需要我们显式地指定@Default:
1)在一个域上指定,以便声明这是一个拥有默认绑定类型的注入域,以及在一个
2)WebBean上指定,这个WebBean除了默认的绑定类型之外还拥有其他的绑定类型。
简而言之,如果你需要注入的类有绑定类型,那么就无需使用@Default,否则就需要使用@Default指明此处为注入点.9.
关于UnproxyableDependencyException :
WebBean管理器通过一个代理对象来间接地拥有所有注入的WebBean引用。这个客户代理负责确保收到方法调用的WebBean实例就是当前上下文相关联的实例。客户代理也允许诸如绑定到会话上下文的WebBean可以序列化到硬盘中,而无需递归地序列化注入到这个WebBean中的其他的WebBean。
如果注入点的类型无法被代理的话,WebBean管理器会抛出一个UnproxyableDependencyException异常。
下面的Java类型无法被WebBean管理器代理:
1)声明为final的类或者拥有final方法的类,
2)没有无参非私有构造器的类,以及数组和原始类型。(针对POJO)
修正 UnproxyableDependencyException 很容易。只需简单的想注入类添加一个无参构造器,引入一个接口或者将注入的Web Bean的范围 @Dependent 即可。10.
生命周期回调方法 :
Webbeans本身借鉴了EJB的对生命周期管理的特性,是POJO具有”stateful”特性.
对于企业级webbeans即(EJB会话bean),仍然就有EJB的所有生命周期回调方法: @PostConstruct, @PreDestroy, @PrePassivate 和 @PostActivate。(备注:stateful,stateless会话bean的回调方法有部分差异,请参见EJB)简单webbeans(POJO),仅仅具有@PostConstruct 和 @PreDestroy 回调方法.
不过EJB和POJO的webbeans都可以使用@Resource, @EJB 和 @PersistenceContext 来分别注入Java EE资源,EJB和JPA持久化上下文。简单的Web Bean不支持使用 @PersistenceContext(type=EXTENDED) .
11.
InjectionPoint 对象(内置) :
一个 @Dependent 范围的Web Bean可以注入一个 InjectionPoint 实例并且访问这个注入点相关的元数据。其实是利用了java的反射机制.InjectionPoint中有用的方法:
1)getAnnotated():获取注入域或者参数的实例.
2) GetMember():获取注入域对象.类似反射机制的getMember().12.
Web Beans定义了四个内置范围 :
1)@RequestScoped
2)@SessionScoped
3)@ApplicationScoped
4)@ConversationScoped
当然webbeans可以自定义范围,前提是你需要对容器context机制有较深 理解.@Dependent范围是默认范围,它的生命周期依赖它所在的对象。13.
对话范围(Conversation) :
对话范围类似于会话范围(session),都可以跨越多个请求.但是session创用来存储用户相关的状态.
对话范围往往与一个特性的web页面关联,即维护页面状态.
从用户角度,用户的每次通过web页面的操作,均会执行:请求—产生服务—响应—渲染页面.对于request范围内的数据,将会在请求结束后被销毁,无法在响应阶段继续保持.但是如果放在session中,将会是一个很大的性能开支.
对话可以代表一个任务,或者一个工作单元.说白了,就是一次有意义的”问--答—确认”过程.对话将会在请求响应即页面渲染之后结束.
对于长对话,可以跨越多个请求,数据得到保持.开启长对话通过”conversation”webbeans的@begin,结束@end.(@begin,@end注释在conversationScoped范围的类方法上).14.
@New注释 :
允许注入点隐式的定义一个依赖的webbean,其范围为@Dependent.如:@New Shop shop;通过使用@New注入一个Shop实例,这个shop实例不会共享上下文中其他shop实例,即注入之前new一个新的引用.并且@New的对象会和所依赖的webbean具有相同的生命周期,即使注入对象有自己的生命周期.
@NewShopshop1;
@DefaultShopshop2;
@Default Shop shop3;如上,shop2和shop3源于同一个实例引用,他们具有相同的生命周期.shop1和shop2/shop3是不同的实例,可能具有不同的生命周期,取决于所依赖的webbeans.
15.
生产者方法:
@Produeces 注释的方法, 默认的生产者方法的范围是 @Dependent,所以Web Bean管理器每次注入这个域或者注入任何其他对应该生产者方法的域的时候,这个生产者方法都会被调用。这样,对于每个用户会话,我们有可能有多个PaymentStrategy实例。要改变这种行为,我们可以给这个方法添加一个 @SessionScoped 注释。
@produces @Shop @SessionScoped Public Shop finadShop(ShopItem item){…}
注意:对于生产者方法,如果需要有效的注出,最好对返回值加上绑定类型.如果需要共享某范围的实例,你可能需要添加范围注释.这样可以保证在同一范围内不会构造第二个实例.
当然你可以有更多的选择,在注入item的时候,你可以使用@Current注入默认范围的item,也可以使用@New注入是创建新的item,或者给item添加范围控制..等等.其他weld的高级特性,稍后给大家解析..谢谢各位.