2011年10月21日星期五

JavaEE_007:JavaEE6 新特性之一:EJB3.1

1. 无需Local Interface,Remote Interface可根据需要选择
POJO类 + 元注释 = EJB。例如:
@Stateless
public class HelloBean {
public String sayHello() {
String message = “hello");
return message;
}
}

取消Local Interface的原因是因为本地其它模块在调用该EJB时,需要细粒度访问该EJB。
这样的话,与其定义一个Local Interface暴露一大堆细粒度方法,不如让本地其它模块直接访问该类。
而Remote Interface一般是粗粒度调用,所以不必暴露那些细粒度的方法。

使用依赖注入的方式调用EJB,引用类型就是POJO类。例如:
@EJB private HelloBean helloBean;
...
String msg = helloBean.sayHello();

2. 增加单例模式的Session EJB
Singleton Session EJB 确保在一个JVM中只有一个EJB实例。
可以用来在应用中共享状态。例如:
@Singleton
public class CachingBean {

private Map cache;

@PostConstruct void init() {
cache = ...;
}

public Map getCache() {
return cache;
}

public void addToCache(Object key, Object val) {
cache.put(key, val);
}
}

默认情况下,EJB容器保证Singleton Session EJB是线程安全的,即同一时刻只允许一个线程访问该EJB,其它线程将被阻塞。
如果想要允许并发Singleton Session EJB,需要增加@ConcurrencyManagement元注释。

3. 支持异步调用Session Bean 方法
EJB容器为了让EJB的行为可控,不允许编写多线程的EJB,因为可能会引起无法预料的异常情况。
所以以前的EJB方法都是同步的,当然你可以使用Message Driven Bean来达到异步通信的目的。
但毕竟Message Driven Bean需要配置其它资源如Queue/Topic,并且需要实现其指定的Interface。
现在好了,你可以通过在EJB方法上增加@Asynchronous,就可以异步的调用该方法了。例如:

@Stateless
public class OrderBean {

public void createOrder() {
Order order = persistOrder();
sendEmail(order); // fire and forget
}

public Order persistOrder() {...}

@Asynchronous
public void sendEmail(Order order) {...}
}

异步方法可以返回一个java.util.concurrent.Future,Future对象容纳了异步操作返回的结果。
你可以访问Future对象,通过get()方法获取返回值、捕捉异常、取消该异步调用。
你也可以其它类型的返回值,如AsyncResult,它实现了Future接口。例如:
@Stateless
Public class CalculatorBean implements CalculatorService {

@Asynchronous
public Future performCalculation(...) {
// ... do calculation
Integer result = ...;
return new AsyncResult(result);
}
}

思考:异步调用Session Bean 方法的原理是怎样的?

4. 简化EJB打包规则:EJB可以直接打进.war包中
EJB不必再打进ejb jar包中,可以直接打进.war包中。
这意味着你可以将EJB类放到WEB-INF/classes目录下,或者放到WEB-INF/lib目录下的一个.jar文件中。
EJB部署描述符也是可选的,如果你需要它,你可以将EJB部署描述符打包到WEB-INF/ejb-jar.xml文件中。


思考:部署描述符和元注释哪个优先级高?

5. 增强Timer Service
提供了类似Cron语法的Schedule定义。例如:
second [0..59], minute[0..59], hour[0..23]...
dayOfMonth[1..31]
dayOfWeek[0..7] or [sun, mon, tue..]
Month[0..12] or [jan,feb..]

@Stateless
public class WakeUpBean {

@Schedule(dayOfWeek="Mon-Fri", hour="9")
void wakeUp() {
...
}
}

思考:EJB Timer Service与Quartz相比,优势在哪里?

6. 提供轻量级EJB:EJB Lite
EJB毕竟是一个“很重”的服务器端组件,很多应用实际用不到EJB完整的功能。
为此,EJB 3.1中提供了一个轻量级EJB:EJB Lite,它是EJB API的一个子集。
EJB3.1 与 EJB Lite的功能对比如下图。

EJB Lite提供了厂商选项,让各大应用服务器厂商可以定制化实现自己的EJB Lite。
使用EJB Lite开发的应用同样可以部署到任何支持EJB的服务器上。

7. Portable JNDI Name
在Java EE 6之前,不同厂商对JNDI 的命名方法各不相同,给开发人员造成了一些不便。
为此,JavaEE6规范了JNDI的路径语法如下:
java:global[/]//
java:app[/]/
java:module/
其中,global :全局可见;app:同一个应用可见;module:同一个应用模块可见。
因此,开发JavaEE6应用时,请遵守新的JNDI命名规范。

Portable JNDI name举例:
(1)Client inside a container (use DI)
@EJB Hello h;
(2)Client outside a container
Context ctx = new InitialContext();
Hello h = (Hello) ctx.lookup(xyz);
(3)Portable JNDI name is specified
java:global/foo/bar/HelloEJB

8. Embeddable EJB Container
允许在JavaSE中创建EJB Container,也就是说,不用把EJB部署到应用服务器就可以测试EJB。
此时JavaSE客户端和EJB在相同的JVM中运行,如下图所示。

这为测试,批处理过程和在桌面应用程序中使用EJB提供了很大的方便。
public static void main(String[] args){
EJBContainer container = EJBContainer.createEJBContainer();
Context context = container.getContext();
Hello h = (Hello)context.lookup("Global_JNDI_Name");
h.sayHello();
container.close();
}

9. Interceptors and InterceptorBinding

10. Singletons can be chained

11. Non persistent timer

12. @StatefulTimeout

参考文献:
1. http://11643599.blog.hexun.com/55545584_d.html
2. http://developer.51cto.com/art/201001/179588.htm
3. http://developer.51cto.com/art/200907/138734.htm
4. http://developer.51cto.com/art/200906/127156.htm
5. http://javahowto.blogspot.com/2010/11/programmatically-bind-global-jndi.html
6. http://www.ofmclub.com/content/java-ee-6%E4%B8%AD%E6%96%B0%E5%A2%9E%E7%9A%84jndi%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4

没有评论: