欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

EJB3.1新特性 博客分类: ejb3 webbeansBeanJPAEJB编程 

程序员文章站 2024-02-20 11:59:16
...
这个系列的文章是EJB3.1专家小组正在开发的下个版本JavaEE规范的预览。EJB3.0去掉了沉重的编程模型而带给Java EE 5一个更简单的编程环境。EJB3.1目标是在EJB3.0带来的成功之上,将简单开发深入下去并增加一些急需的特性。
在这第一篇文章中,我将涵盖已经讨论的很深入的两个特性——选择性的为EJBs和Singleton Bean创建接口。同时,我也将提到一些已经开始考虑的可能出现的新特性。记住,所有的这些都不是最终版本。

EJB 接口是可选择的
首先得一个改变是把Session Bean 接口变成可选的了——让EJBs真正像是POJOs——去掉了最后遗留的障碍。
基于接口的编程确实是书写松耦合,单元可测试的应用的一个有用的技术。这正是EJB2.1和Spring推崇组件接口的原因。事实上,就算是EJB3.0 Session Beans 也至少需要一个接口。
这样做的麻烦是组件接口在很多情况下其实并不需要。在更多的情况下,一个简单的Java对象正是你最需要的,尤其是在你不需要做过多的单元测试和松耦合并不是应用的最核心要求的时候。
EJB3.1允许你这样做。现在,Session Beans不需要任何的接口,就象JPA Entity 和Message Driven Beans。所有你需要做的就是给一个POJO标记上@Stateless或者@Stateful来得到所有的EJB功能。下面是一个根据《EJB 3 in Action》中Session Bean章节的一个列子修改的:

@Stateless public class PlaceBidBean {
@PersistenceContext
  Private EntityManager entityManager;
  public void placeBid (Bid bid) {
   entityManager.persist(bid);
  }
}下面为这个bean添加了一些新的特性:

@Stateless @WebService
public class PlaceBidBean {
  @PersistenceContext
  private EntityManager entityManager;
@WebMethod public void placeBid (Bid bid) {
    entityManager.persist(bid);
   }
}在上面的例子中,我们使用JAX-WS 2.0吧placeBid方法发布为一个web service。同时我们使用JPA来持久化一个Bid entity。PlaceBidBean拥有了所有无状态Session Bean的功能,包括在后端的对象池、线程安全、组件生命周期、拦截器、安全和声明事务。比如,如果你对EJB3.0熟悉的话,你会想placeBid方法是默认的被一个容器管理的JTA包装起来的。该bean同时也可作为RMI基础的远程端。
除了能和简单的bean类型一起工作,去掉接口也让EJB3.1 beans在WebBeans中简单实用。WebBeans(JSR 299),在JBoss Seam中得到大量灵感。WebBeans无缝的集成了JSF,JPA和EJB3.1,从而让Java EE 6整整的变成了一个整体。


Singleton Beans
EJB3.1 Singleton Beans 是何GOF Singleton 模式相等的组件。在Java EE 上下文中,他们被用来保存应用级别的共享数据。想象你需要缓存一些数据在内存中而不是重复的从数据库中反复的查询。Stateless Session Beans和Stateful Session Beans 都不能达到这种需求。虽然Stateful Session Beans可以拥有session级别的缓存,但它的数据不能再整个应用级别其他的组件轻松访问。
有很多种方法可以满足这种需求,一种简单的办法就是使用static 属性或者GOF Singleton模式的POJOs。一种稍微复杂的解决思路是使用Servlet容器的Applcation级别空间,JBoss Cache,OSCache,JCS和SwarmCache等。商业的解决方案包括Tangosol Coherence和Terracotta。虽然这些方法在大部分情况下很有用,但是他们也存在很多的不足。一些不是线程安全的(static fields,Singleton POJOs),一些不支持事务的(Singleton POJOS,Servlet application scope,OSCache,JCS,SwarmCache),这些都不支持远程并且没有任何安全机制。除了这些通用的解决方案之外,现在可以使用Enter EJB3.1 Singletons来解决。
容器用来保持对一个EJB3.1 Singleton实例的唯一性。这意味着Singletons可以保存应用层中的状态。因为是一个EJB,所以,Singleton拥有所有的中间服务——声明事务管理,安全,远程,线程管理,依赖注入,组件生命周期回调,拦截器等等。和其它的EJBs一样,Singleton也是标注性POJO。下面是一个例子:

@Singleton
public class DiscountRateBean {
@PersistenceContext
private EntityManager entityManager;
private Rate rate;
@PostConstruct
private void init() {
rate = entityManager.find(Rate.class, 1);
}
@PreDestroy
private void destroy() {
entityManager.merge(rate);
}
public void setRate(Rate rate) {
this.rate = rate;
}
public Rate getRate() {
return rate;
}
}在这个列子中使用了JPA和bean生命周期回调在启动阶段加载数据,并在bean销毁的时候保存其值。所有的调用getRate和setRate的方法都是直接连接到DiscountRateBean的唯一实例的共享数据。你将会发现一个有趣的问题——如果容器没有调用pre-destroy回调方法的机会,任何一个修改都可能丢失。我们将在下面的文章中介绍怎么通过一个类似于Corn的定时器(cron-like timers)来减小这种问题。
默认的,所有的Singleton方法都是现成安全的并且支持事务。这意味着多线程的调用这个bean是有序列的,并且所有的方法都假设带有一个REQUIRED的事务属性。你可以通过使用@TransactionManagement和@TransactionAttribute标签来改变事务的类型——就像你在Stateful或者Stateless Session Bean中那样。如果你在现实中接触过大规模应用的话,你会知道吧getRate和setRate方法都列队的访问,是很大的一个性能瓶颈。现实中,我们会在getRate方法上使用一个只读锁并且在setRate方法上使用一个读-写锁。你可以使用@ConcurrencyAttribute实现:

@Singleton
public class DiscountRateBean {
@PersistenceContext
private EntityManager entityManager;
private Rate rate;
@PostConstruct
private void init() {
rate = entityManager.find(Rate.class, 1);
}
@PreDestroy
private void destroy() {
entityManager.merge(rate);
}
@ConcurrencyAttribute(READ_WRITE_LOCK)
public void setRate(Rate rate) {
this.rate = rate;
}
@ConcurrencyAttribute(READ_LOCK)
public Rate getRate() {
return rate;
}
}熟悉Doug Lea's工作的人都知道,READ_LOCK和READ_WRITE_LOCK术语来自于java.util.concurrent。一些应用的共享数据确实是只读的,任何锁其实都不是必要的。在这种情况下,你只需要创建unsynchronized Singleton:

@Singleton
@ConcurrencyAttribute(NO_LOCK) // READ_LOCK would also work...
public class DiscountRateBean {
@PersistenceContext
private EntityManager entityManager;
private Rate rate;
@PostConstruct
private void init() {
rate = entityManager.find(Rate.class, 1);
}
public Rate getRate() {
return rate;
}
}
@ConcurrencyAttribute(READ_LOCK),@ConcurrencyAttribute(READ_WRITE_LOCK)和@ConcurrencyAttribute(NO_LOCK)的一个改变是这几个标签将更改为@ConcurrencyReadLock,@ConcurrencyReadWriteLock和@ConcurrencyNoLock。为了结合这种基础的标签格式,@TransactionAttribute会分成@TransactionRequired,@RequiresNewTranscation,@TransactionNotSupported等等。不过有些意见认为这样会增加代码的复杂度。
同样,你可能不希望容器来管理Singleton的并发,下面是一个bean manage concurrency的例子:

@Singleton
@ConcurrencyManagement(BEAN)
public class DiscountRateBean {
@PersistenceContext
private EntityManager entityManager;
private Rate rate;
@PostConstruct
private void init() {
rate = entityManager.find(Rate.class, 1);
}
@PreDestroy
private void destroy() {
entityManager.merge(rate);
}
public synchronized void setRate(Rate rate) {
this.rate = rate;
}
public synchronized Rate getRate() {
return rate;
}
}注意这个例子中我们同步的关键字(synchronized keyword)来管理并发。因为容器不需要接口了,所以你可以使用任何你喜欢的同步管理机制,包括但并不仅仅限制为java.util.concurrent包。目前,新的concurrency管理特性仅仅限制于EJB3.1 Singleton.不过可能会扩展到其他的bean上。
Singletons 同样也能通过加载顺序提供延迟/迫切加载,和Singleton的依赖管理。这里我们暂时不讨论这些话题。虽然规范没有提到集群的支持,但因该是集群安全的。

EJB3.1更多的特性
以上提到的两个特点只是冰山一角。还有很多有趣的特性列在JSR议案中,下面是其中一些:
1,在Servlet容器中支持EJBs,包括简单打包选项。目前的想法是允许EJBs放在WEB-INF/classes目录下面,吧ebj-jar.xml放在WEB-INF同级。就象web.xml。同样,你可以把EJB JAR
包放在WEB-INF/lib下
2,EJB Timer服务增强类似CRON的作业调度机制,开发时时间对象创建,Stateful Session Bean使用调度对象标记等。
3,通过Stateful Session Bean web service终点提供有状态的web service。