【翻译】EJB3.1真的来了吗?EJB3.1系列文章(四)

 

前言

 

Raza 同学终于又出 EJB3.1 文章了,真是姗姗来迟,我也是刚翻译出来,希望和大家分享 EJB3.1 的新特性。今天主要讲的是 WebBeans ,相信很多关于 EJB3.1 的人,一定会对它感兴趣的,今天我们谈到 WebBeans 两个方面:依赖注入和增强的拦截器模型。相信今天的文章会让你有所收获。

原文:http://www.theserverside.com/tt/articles/article.tss?l=NewFeaturesinEJB3-Part4

 

 

 

正文

 

WebBeans EJB :如漆似胶

 

 

WebBeans 是当前 JavaEE6 日程安排中最激动人心的 JSRs 规范之一。支持集成 WebBeans 的主张非常有号召力。如果你用过 JSF EJB3.0 来开发应用程序的话, JSF 的那层薄薄 backing bean 一定让你印象深刻。实际上,即使你可以用 @EJB annotation 很容易的将 EJB 注入到 backing bean 的话,那么 backing beans 还是在充当 glue-code 的角色。而 WebBeans 却允许你直接使用 EJB 作为 JSF backing beans ,从而去掉了多余的 glue-code 。在第二小节的时候,我们共同来验证这样的美事吧。

 

 

除了更有效的整合 JSF EJB 编程模型外, WebBeans 当然也少不了提供一系列很酷的特性,包括:

 

<!---->l         <!---->更健壮的基于 annotation 的依赖注入

<!---->l         <!---->越发简洁易用的 JavaEE 拦截器模型

<!---->l         <!---->更加合理的对 Web 应用程序的组件上下文进行管理

 

这里的最后一点我不想多说,因为这里更侧重的是 JSF 而并非 EJB ,但剩下的精彩主题是会一一向大家介绍的。

 

WebBeans 很大程度上受 JBoss Seam Google Guice 的启发。现在该 JSR 规范由 Gaving King Bob Lee 所领导 ( 注:两位绝对是 Java 界响当当的牛人 ) 。我个人觉得,虽然东西到了 JSR 手里肯定会有自己的实现版本,但 Seam 的核心代码仍然是 WebBeans 的基石。

 

 

 

EJB 成为 JSF Backing Beans

 

 

好吧,现在我们从 EJB3 in Action 拿一个例子进行重构,从总体上看看 WebBeans 究竟是什么。在 EJB3 in Action 中,最经典的 Session bean 例子自然还是那个“竞标”例子了 (adding a bid) Session bean 使用了 JPA 将一个 Bid entity( 实体 ) 持久化到数据库。现在我们来看看在 WebBeans 的环境下, session bean entity 变成什么样子了:

 

@Component
@Stateless
@Named("placeBid")
public class PlaceBidBean {
	@PersistenceContext
	private EntityManager entityManager;

      @In
      private Bid bid;

	public void addBid() {
	    entityManager.persist(bid);
	}
}

@Component
@Entity
@Named("bid")
public class Bid {
    private Long bidId;
    private String bidder;
    private String item;
    private Double bidPrice;

    @Id
    @GeneratedValue
    public Long getBidId() {
        return bidId;
    }

    public void setBidId(Long bidId) {
        this.bidId = bidId;
    }

    public String getBidder() {
        return bidder;
    }

    public void setBidder(String bidder) {
        this.bidder = bidder;
    }

    public String getItem() {
        return item;
    }

    public void setItem(String item) {
        this.item = item;
    }

    public Double getBidPrice() {
        return bidPrice;
    }

    public void setBidPrice(Double bidPrice) {
        this.bidPrice = bidPrice;
    }
}

 

 

stateless bean PlaceBidBean Bid JPA entity 使用 @Component annotion ,这样就可以将它们同时注册到通过 WebBeans 容器里去。 @Named annotation 给组件分配的名称可以由 WebBeans 容器识别出来。而这些名称可以直接在 JSF 页面上使用。 ( 注:比如说上面的 @Named(“bid”) 相当于为 Bid 类起了一个别名,这样做的意义在于 JSF 可以用 bid 直接取值了,比如说 #{bid.bidId}, #{bid.bidder} 等,与 Struts2 需要写一大堆 set,get 方式相比,确实精简不少。 ) bid 实例变量上的 @In annoation 是告诉该 session bean bid 是注入进来的。我相信到这里,你应该很清楚在使用 WebBeans 组件后,相应的 JSP 页面代码会是怎么个情况了吧。图一,显示了一个实际竞价页面:

 

<html>
  ...
  <body>
    <f:view>
      ...
      <h:form>
        <table>
          <tr>
            <td>Bidder</td>
            <td><h:inputText value="#{bid.bidder}"/></td>
          </tr>
          <tr>
            <td>Item</td>
            <td><h:inputText value="#{bid.item}"/></td>
          </tr>
          <tr>
            <td>Bid Amount</td>
            <td><h:inputText value="#{bid.bidPrice}"/></td>
          </tr>
        </table>
        ...
        <h:commandButton type="submit" value="Add Bid" 
            action="#{placeBid.addBid}"/>
        ...
      </h:form>
      ...
    </f:view>
  </body>
</html>

 

 

【翻译】EJB3.1真的来了吗?EJB3.1系列文章(四)

 

 

 

正如你所看到,使用 EL 绑定在 JSF 页面上的 bidder item bid amount 字段都与 Bid entity 的属性是一致的。而“ bid ”和“ placeBid ”匹配的就是 @Named 所标注过的组件。当 WebBeans 第一次遇到符合 @Named 所标注的 Bid 实体时,它会在隐式的在后台创建一个 Bid 的实例,并将压入 request context ,供页面使用。同时你还要注意到 PlaceBidBean.addBid 方法也已经作为一个 action listener 绑定在 JSP 页面的添加按钮上。当按钮点击时,触发表单提交, WebBeans 所绑定的表单值又会自动依次中填充回 Bid 实体的各个属性,这一切还得归功于 @In annoation 。与 Bid entity 不同的是, EJB 这一块会从 JNDI look up PlaceBidBean ,然后将它放入 reqeust context 中。当添加按钮触发后, addBid 方法就会被调用, EJB 马上就会使用 JPA entity manager 来保存注入的实体。除了 request , application, session context, WebBeans 来发明了“ conversation context 。关于这些 contexts 的更多细节,请参看 WebBeans 的草案。

 

 

单凭以上代码就吹捧 WebBeans 编程模型的确没有多大的说服力。 WebBeans 用一种方法将 JSF,EJB JPA 整合起来,让人感觉这似乎是一个真正的 JavaEE 无缝开发平台。它的 out of box( 即拆即用 ) ,最小化 boilerplate code ,让你如同正在使用像 Ruby on Rails 这样的框架。你是不是这样看待的呢?你觉得还是这样很牵强?这样的模型有缺陷吗?

 

 

 

WebBeans 的依赖注入

 

 

绝大部分的企业应用程序组件无非就是: service 组件, DAOs 以及 domain model 组件。一般来说, JPA 是实现 domain model 组件的最佳选择;而 service DAO 组件又是 EJB 的不二选择。因为 EJBs 默认具备事务和线程安全的特性。 ( 很多人其实错误的认为 EJBs 默认也是支持 remote 的,这不是真的。 ) 如果你要使用声明式的 security remoting web services messaging scheduling 或者 asynchronous processing 的话, EJB 其实显然是一个更具优势的组件。上述这些 services 我们已经完全以 annoation 的形式给封装好成 EJB 组件了。

 

 

尽管如此,在一个应用程序里,总是还有一些组件并根本不需要声明式 servies ,不需要事务的感知 (transaction-aware) ,也不需要显式的线程安全保证。就拿 utilities helper 组件来说吧,它们确实没有必要。因为 EJB3.0 对那些非托管的组件,并不支持依赖注入,因此不把它们也搞成 EJB ,是没法直接使用依赖注入的。 WebBeans 的依赖注入很好的解决了这个问题——因为 @Component annoation 可以运用于任何 POJO 对象,不再局限于 EJBs JPA 实体了。刚才的咱们不就用 @In annoation Bid entity 注入到 PlaceBidBean 这个 stateless session bean 中去了吗?因此, WebBeans 同样可以将普通的组件注入到 EJBs 中去了

 

 

现在我们还是快速来看一个例子。假设用户输入的 bid amount 属性需要先通过一个 utility 类进行四舍五入到小数点两位,然后再保存,那么我们可以这么做:

 

@Component
public class MathUtil {
    ...
    public static double round(double value, int decimalPlaces) {
        BigDecimal converter = new BigDecimal(Double.toString(value));
        converter = converter.setScale(decimalPlaces, 
            BigDecimal.ROUND_HALF_UP);
        return converter.doubleValue();
    }
    ...
}

@Component
@Stateless
@Named("placeBid")
public class PlaceBidBean {
	@PersistenceContext
	private EntityManager entityManager;

      @In
      private Bid bid;

      @In
      private MathUtil mathUtil;

		public void addBid() {
          bid.setBidPrice(mathUtil.round(bid.getBidPrice(), 2));
	   	 	entityManager.persist(bid);
	}
}

 

 

在这个例子里,当 EJB 需要时,一个新的 MathUtil 的实例会被创建,然后注入到相应的 EJB bean 中去。尽管普通的 WebBeans 组件无法直接使用 EJB 的声明式 services ,但他们可以使用自己的依赖注入,生命周期回调( life-cycle callbacks ,使用 @PostConstruct/ @PreDestroy 实现)以及 interceptoer

 

@In @Component annotations 还只是冰山一角。 WebBeans JavaEE 带来了一套完整的依赖注入特性,包括 Guice 风格的方法创建和 annoation 绑定。注意所有的 EJB 类型包括消息驱动 Bean 都可以使用 WebBeans 特性。

 

 

 

WebBeans Interceptor Enhancements

 

 

相对于 EJB 来说, WebBeans 另一个主要的特性就是对现有 interceptor model( 拦截器模型 ) 的扩展。现在你可以直接在 EJBs 中使用 @Interceptor @Interceptors annotations 了。这样的结构既优雅又直接,不过不是非常灵活。 WebBeans 在些基础上,通过使用 annoation, ,引入了更加灵活的 Interceptor 机制,却没有仍然没有增加什么复杂度。理解它的最好方法还是代码。现在假设我们想使用一个 auditing interceptor 来拦截 EJB PlaceBidBean ,我们可以这么做:

 

 

 

@InterceptorBindingType
@Target({TYPE, METHOD})
@Retention(RUNTIME)
public @interface Audited {}

@Audited @Interceptor
public class AuditInterceptor {

    @AroundInvoke
    public Object audit(InvocationContext context) throws Exception {
        System.out.println("Entering: "
            + context.getMethod().getName());
        System.out.println("  with args: "
            + context.getParameters());
        return context.proceed();
    }
}

@Component
@Stateless
@Named("placeBid")
public class PlaceBidBean {
	@PersistenceContext
	private EntityManager entityManager;

      @In
      private Bid bid;

      @Audited
	public void addBid() {
	    entityManager.persist(bid);
	}
}
 

 

 

@Audited annotation 上面的那个 @InterceptorBindingType annotation 是用来声明它要绑定到一个 interceptor 上。与 EJB3.0 interceptor model 不同的是, WebBeans 通过使用 @Interceptor annotation 将一个 interceptor 绑定在一个或更多的 annotations 上。因此 @Audited @Interceptor annotations 同样放在 AuditInterceptor 上面表示凡是标注了 @Audited 的组件或方法都会被拦截器拦截。因此,当 placeBid 方法被调用时, AuditInterceptor 先会触发 audit 方法的执行。

 

 

除了它的间接性与灵活性外,我觉得这个扩展真的让代码变得更加可读。你觉得呢?是不是 EJB 规范也应该采纳这个扩展,正式成为 JavaEE 整体中的一部分呢?

 

 

 

继续工作

 

由于 JavaOne 大会的原因,专家组进度慢了下来也是情有可原。但不管怎么说,还是要言归正传,回到正常的工作中来。还有很多有趣的主题正在激烈的讨论着,它们是:

 

<!---->l         <!---->标准 JNDI 的映射机制同时由 JavaEE6 EJB3.1 两个专家组同时进行讨论。相信将来这一块应该没有多少水份。(笑:难道 JSR 专家组们自己觉得自己的东西都很有水份?)

<!---->l         <!---->支持 JavaSE 环境也可以使用 EJB3.1 (比如说单元测试)的工作仍然在进行着。实际上,继 OpenEJB EasyBeans Embedded JBoss 的路线之后, Embedded GlassFish 的动作也强烈的表明了它的决心。

<!---->l         <!---->一个很牛的扩展机制下在 JavaEE6 专家组中炸开了锅。而且好像它还是本次专家组的讨论最后一个 Big Thing 。如果通过审核,那么就会为 JavaEE 社区提供一个非标准的第三方基于 annoation 的声明式 services 组件。 BTW :究竟是什么,这么神秘, Raza 也真会“炒作”啊,呵呵)

 

你是怎么看待这些特性的?如果你觉得它们很重要,请大胆发表你的意见,并给专家组发 Email EJB3.1 专家组的电子邮件 [email protected] WebBeans 专家组的电子邮件是 [email protected] 。也可以随时给我 [email protected] 发邮件。在此期间,我还会继续给你们介绍接下来专家组们正在讨论的特性,也许是本系列的最后一篇了。敬请期待。

 

 

 

参考

 

 

  1. New Features in EJB 3.1, http://www.theserverside.com/tt/articles/article.tss?l=NewFeaturesinEJB3-1 .
  2. New Features in EJB 3.1 - Part 2, http://www.theserverside.com/tt/articles/article.tss?l=NewFeaturesEJB31 .
  3. New Features in EJB 3.1 - Part 3, http://www.theserverside.com/tt/articles/article.tss?l=NewFeaturesEJB31-3 .
  4. JSR 316: Java EE 6, http://jcp.org/en/jsr/detail?id=316 .
  5. JSR 318: Enterprise JavaBeans 3.1, http://jcp.org/en/jsr/detail?id=318 .
  6. JSR 299: Web Beans, http://jcp.org/en/jsr/detail?id=299 .
  7. Seam, http://www.seamframework.org .
  8. Google Guice, http://code.google.com/p/google-guice/ .

你可能感兴趣的:(ejb,JSF,jpa,seam,webbeans)