【转】关注CDI(上下文依赖注入):Weld, Seam 3及之后

Eye on CDI:Weld, Seam 3 and Beyond

Bill Bendrot    2010年6月



目标:

  • JEE的长期挑战
  • 我有一个解决方案,但是……
  • CDI是什么?
  • Weld
  • Seam 3

JEE的长期挑战

太多bean,太少的共同基础……

关注CDI:Weld, Seam 3和Beyond - *工* - 要有光,于是就有了光
 

上下文滥用!—— HttpSession —— 为什么?

关注CDI:Weld, Seam 3和Beyond - *工* - 要有光,于是就有了光
 
  • Servlet上下文模型太粗。
  • 不能反映现实世界的用法。

我有一个解决方案,但是……

  • Seam提出:
    • 转变任何东西为一个“组件”。
      • 一类“东西”。
    • 引入双向注入。
      • 使依赖注入为有状态的和动态的。
    • 结合了JSF和EJB。
    • 增加了对话上下文和业务流程上下文。
  • 但是,Seam仍然是非JEE 的。

解决方案:上下文和依赖注入

  • JSR-299 —— 用于JEE的上下文和依赖注入。
    • JEE6的核心部分。
    • 帮助统一bean模型。
    • 明确定义的上下文,可以绑定有状态bean给它们,并管理生命周期。
    • 增加依赖注入给JEE,并使它成为类型安全。
    • 引入了一个事件通知系统。
    • 使用拦截器,鼓励松耦合。
      • 重新定义拦截器为装饰器,用于细粒度控制。
    • 集成统一的EL,桥接JSF。
    • 引入了一个SPI,扩展JEE —— 走向自己的JEE7!

CDI的关系

  • 规范 —— JSR-299 —— CDI
    • 也集成了JSR-330的元素
      • 参考实现  —— Weld
        • TCK ——  技术兼容工具包
          • 实现 —— Seam 3

名字代表什么?解决方案的历史。

  • 开始使用WebBeans。
  • 更多涉及“Web”,而少涉及“Beans”。
  • 规范改为CDI。
  • 参考实现最初称为 WebBeans。
  • 委员会异议。
  • 参考实现最命名为Weld。
  • 当谷歌搜索信息时,你仍然会看见提及到“WebBeans”,并且甚至在规范的文件名仍然是“WebBeans”。

统一Bean模型

关注CDI(上下文依赖注入):Weld, Seam 3及之后 - *工* - 要有光,于是就有了光
 
管理Bean细节

  • 任何被容器管理的组件都是一个Bean。
  • 管理Bean建立的基本规范。
    • 拦截器
    • 生命周期回调
    • 资源注入
  • 在JEE6及之后中,其他的规范建立在这个基础之上。
    • CDI
    • EJB
    • 等等……

CDI Beans —— 我们回到“管理Beans”

  • CDI增加以下内容到管理Bean的服务:
    • 自动发现
      • 通过beans.xml选择加入
    • Bean类型
    • 有一个“家族”的bean类型的能力:
      • Qualifiers (在设计时选择)
      • Alternatives(在部署时选择)
      • Producers(在运行时选择)
  • 域的通告和联接
  • EL名字(可选的)
    • 直接暴露bean给JSFs或JSPs
  • 拦截器绑定

CDI Bean例子

public class Bike {
public String returnManufacturer() {
return "Made by JBoss";
}
}

//相同的Bean作为一个EJB
@Stateful public class Bike {
.....

//
相同的Bean暴露给一个JSF
@Named
public class Bike {
.....

明确定义的上下文 —— 增加了对话

关注CDI(上下文依赖注入):Weld, Seam 3及之后 - *工* - 要有光,于是就有了光
 
Conversation (对话)
多请求,少会话 存在于一个JSF用例的时间长短

@ConversationScoped 

促进从瞬时的到长期的:
Conversation.start() Conversation.end();
上下文模型

@SessionScoped
public class Race() {
@Inject @Motocross Motorcycle racer1
....
}

伪域:
@Dependent
Servlet域:
@RequestScoped
@SessionScoped
@ApplicationScoped
JSF域
@ConversationScoped

对话域

关注CDI(上下文依赖注入):Weld, Seam 3及之后 - *工* - 要有光,于是就有了光
 
@ConversationScoped
public class RentCar { 
  @Inject Conversation conversation; 
  public void rentCar(){
    CODE TO RENT CAR 
    conversation.begin();
  } ...

类型安全的依赖注入

注入现在是基于类型
Bean 注入
分类
基于下面的组合:
  Annotation Type Type Params 消除了基于名字/字符串的注入

近看CDI注入

@Motocross
public class Motorcycle extends Vehicle 
implements Bike<Motorized> {
 …
}

4个方法,这个Bean可以被注入:

 Motorcycle
 Vehicle
 Wheel<TwoWheel>
@Motocross

限定者(Qualifiers)

@Motocross是一个限定者( Qualifier):当你有实现了相同接口的多个Bean时,这是一个区分它们的方法。充当一个绑定类型。

@Motocross
public class Motorcycle extends Vehicle 
implements Bike<Motorized> {
 …
}

@Qualifier
@Retention(RUNTIME)
@Target ({TYPE, METHOD, FIELD})
public @interface Motocross { }

@Alternative

可选择性(Alternatives)作为一个布置时覆盖必须专门启用。然后它们占据了匹配的类型的位置。

@Alternative @Motocross
public class TestBike extends Vehicle 
implements Bike<Motorized> {
 …
}

由beans.xml 
启用:

<alternatives>
  <class>
  org.jbossmotors.mock.TestBike
  </class> 
</alternatives>

生产者(Producers)

生产者方法( Producer method)是一个方法,它充当Bean实例的资源。该方法的声明自身描述了Bean,并且当指定的上下文中不存在实例时,容器会调用该方法获取此Bean的一个实例。

@ApplicationScoped
public class RandomNumberGenerator {
  private Random random = 
                  new Random(System.currentTimeMillis());
  @Produces @Named @Random int getRandomNumber() { 
      return random.nextInt(100);
  }
}

被用来,在运行时,动态地实现一个注入。

生产者字段(Producer fields )是一个更简单的可选方法。用于JEE组件参考注入特别好。

@Produces @WebServiceRef
   (lookup="java:app/service/Catalog") Catalog catalog;

事件通知

表示生产者与观察者完全解耦的一种方式,反之也然。

生产者: DeliveryTracking.java

@Inject Event<Package> delivered;
public void delivery(String recipient) {
delivered.fire(new Package(recipient, timeStamp) );
}

接受者: DeliveryNotifier.java

void onDelivery(@Observes Package package,
                        @Default Recipient recipient) { 
      System.out.println(recipient + 
                “ recieved “ + package.getContents()); 

统一的确EL集成

  • 统一的EL暴露管理的Beans给JSF和JSP视图。
    • 所有需要的一切是 @Named注释。
  • 大多数资源是可注入的:
    • 管理的Beans
    • 网页服务参考
    • 本地或远程EJBs
    • 生产者创建的对象
    • 等等
Weld

  • CDI参考实现。
    • “普通(Vanilla)” CDI
  • CDI实现是在JBoss AS 6 和GlassFish 3 中。
    • 但是也支持Tomcat和Jetty,甚至也支持JavaSE
  • 被maven化。
  • 提供扩展的基础。
    • Weld 扩展是用于扩展核心。

关注CDI(上下文依赖注入):Weld, Seam 3及之后 - *工* - 要有光,于是就有了光
 
接下来都会去什么地方?—— Seam 3

  • 现在,Seam在核心利用CDI被模块化。
    • 模块有一个独立发行的周期。
    • 普通的快照/包装发行。
  • Seam堆栈由以下内容构成:
    • Java EE集成在平台内部。
    • 声明性安全。
    • 页面流(jPDL)和业务流程(jBPM)。
    • JavaScrip远程处理。
    • “渲染” e-mail, 图形, PDF, 和 XLS
    • Spring集成,等等。
  • 工具化。

从Seam 2 到 Seam 3

  • Seam 3 = Java EE的可移动扩展。
  • 构建在CDI 基础的顶部。
  • 现在以模块方式组织。

关注CDI(上下文依赖注入):Weld, Seam 3及之后 - *工* - 要有光,于是就有了光


 Seam 3 模块

关注CDI(上下文依赖注入):Weld, Seam 3及之后 - *工* - 要有光,于是就有了光
 
Seam 3 vs. Seam 2

  • 已改变的注释。
    •  @In 现在为 @Inject, @Name 现在为 @Named。
    •  @ScopeType 由域注释替换 ——  @RequestScope 。
    •  @Begin/@End 调用对话接口,现在为了—— Conversation.begin() 。
  • 一些概念/实现被取代。
    • Outjection(注出)—— 不是注出某些东西到域内部,而是确保你正在从该域中读取。
      • 此外,可使用更安全的生产者字段(Producer Fields)替代。
    • 工厂(Factories) —— 来自生产者方法的更安全的结果。

最新的信息

  • http://www.seamframework.org
    • 下载
    • 文档
    • 论坛和社区
    • 投稿

小结

  • JSR-299 —— 引入了一个灵活的JEE 服务集合:
    • 强壮类型的管理的Beans。
    • 上下文。
    • 动态的依赖注入。
    • 多渠道的松耦合。
    • 可扩展的SPI。
  • Weld是 CDI的参考实现,并且在JBoss 6 和 GlassFish3 中被实现。
    • 可以被添加到Tomcat, Jetty。
  • Seam 3 —— JEE的可移动扩展(通过CDI)
展开阅读全文

没有更多推荐了,返回首页