写点什么

Java EE 6:EJB 3.1 的变化引人注目

  • 2010-02-17
  • 本文字数:4546 字

    阅读完需:约 15 分钟

Enterprise Java Bean 3.0(EJB 3)规范为 Java 企业级开发画上了浓墨重彩的一笔,规范的制订是非常透明的,很多想法都来源于社区。它代表了更加一致的服务模式,大量使用 POJO 的同时降低了复杂性。Java 5 的注解间接地成就了这种模式,在使其变得更加强大的同时也减少了开发者的工作量。对于各种新的解决方案来说,EJB 3 抛弃了那些差劲的决策,因此会对那些曾经回避 EJB 的开发者产生极大的吸引力。EJB Entity Beans 不见了,取而代之的是 JPA Entity。EJB 2.1 及更早版本所需的大量 Java 类和接口不见了。默认的“约定优于配置”得到了广泛的应用,这样人们上手就会非常快。EJB 3.0 是一场真正的革命。

如果说 EJB 3.0 是一场革命,那么 EJB 3.1 则是一种进化。EJB 3.1 的一些新特性似乎应该放到 EJB 3.0 中,大家应该原谅规范制定者所持有的谨慎态度——让 80% 的内容能够运转良好要比废弃掉规范中某个差劲的模式要好很多,宁缺毋滥。当然了,其发布时机还是不错的。虽然提供了大量的新特性,但 EJB 3.1 规范及所有的向后兼容和补充说明加起来一共才 626 页,比 10 年前的 EJB 2.1 规范少了 14 页。

我们将在本文介绍这些新特性及其使用方式。

EJB 3.1 的新特性

EJB 3.1 最大的变化并不是向平台增加了很多新特性,而是简化了平台的使用。其中一些扩大了用户所用 API 的范围以提升灵活性;另一些只是带来了更多的灵活性而已。

Singleton

Singleton 是一种新型的 Session Bean,提供了一个额外的保证:每个 JVM 上的 Bean 只会被创建一次。该特性在很多地方都有用武之地,比如说缓存。此外还保证每个资源只有一个共享视图存在,而应用服务器并没有提供该特性。无需持久化的有价值的数据可以通过简单存储实现,因为重新创建的代价可能会很大。来看一个具体的示例吧。假设其他地方已经创建好了 User 实体(或许使用了 JPA 2.0)。

复制代码
@javax.ejb.Singleton
public class ChatRoom {
private java.util.Map<User,Collection<String>> userComments;
@PostConstruct
public void setup (){
userComments = new java.util.concurrent.ConcurrentHashMap<User,Collection<String>>();
/* ...*/
}
public void join(User usr){ /* ...*/ }
public void disconnect(User usr){ /* ...*/ }
public void say(String msg){ /* ...*/ }
}

所有的客户端都可以通过 ChatRoom 实例的引用来更新同一个可变的状态。可以保证的是客户端所获得的实例是一样的。由于这是一个 Session Bean,因此与其他 Session Bean 一样都是线程安全的。

复制代码
@javax.ejb.EJB
private ChatRoom chatRoom ;
/* ... */
chatRoom.join(myUser) ;
chatRoom.say( "Hello, world!");
chatRoom.disconnect();

设计 Singleton 的目的就是用于并发访问。规范赋予了开发者复杂的控制手段来解决并发访问问题。我们可以通过容器以声明的方式指定某种访问类型,该行为是默认的;可以通过注解 @javax.ejb.ConcurrencyManagement(CONTAINER) 显式指定使用容器管理的并发手段。如果想对 Bean 进行更多的控制,请使用 @javax.ejb.ConcurrencyManagement(BEAN)。凭借容器管理的并发手段,我们可以在方法或类层次上指定访问类型。可以在默认情况下于类层次上使用 @javax.ejb.Lock(WRITE) 注解以保证所有的业务方法都是可序列化的,然后针对特定的“只读”方法再进行优化,这么做不会产生任何的副作用。对于只读方法需要使用注解 @Lock(READ)。对于 @Lock(WRITE) 注解所修饰方法的所有访问都是可序列化的,同时会阻塞客户端的访问直到前一个访问完成,或是出现超时的情况。可以通过 @AccessTimeout 注解指定超时的时间,该注解需要一个 java.util.concurrent.TimeUnit 值。现在我们可以使用这种并发控制了,先删除之前的 ChatRoom 实现代码。

复制代码
@javax.ejb.Singleton
@javax.ejb.Lock(WRITE)
public class ChatRoom {
private java.util.Map<User,Collection<String>> userComments;
@PostConstruct
public void setup (){
userComments = new java.util.concurrent.ConcurrentHashMap<User,Collection<String>>();
/* ...*/
}
public void join(User usr){ /* ...*/ }
public void disconnect(User usr){ /* ...*/ }
public void say(String msg){ /* ...*/ }
@javax.ejb.Lock(READ)
public int getCountOfActiveUsers(){ /* ... run through the map and count ... */ }
}

显然现在这个 ChatRoom 实现还是有问题的:一旦用户和帖子的数量超出了应用服务器所能承受的内存极限就会出现内存不足的问题。可以使用过期(expiration)机制来解决这个问题。为了能说的明白点,假设有一个垃圾收集器周期性地检查 ChatRoom 的帖子并根据 LRU 原则(或是使用 JPA 和 EntityManager.persists,然后再销毁)销毁过期的聊天数据。

EJB Timer

从 EJB 2.1 开始 EJB 就拥有一个 Timer 机制,然而遗憾的是该机制总是使用毫秒间隔数,用起来也十分不爽。EJB 3.0 对此进行了一些改进,但本质上却没有什么改变,还是基于时间间隔。因此,如果想在每周的开始执行一项活动就比较难办了。EJB 3.1 对此又进行了一些改进,提供了一种声明式、灵活的定时器服务并参考了其他调度器,如 Quartz 和 Flux。对于大多数简单的调度来说(包括 CRON 风格的调度),EJB 3.1 是一个完美的解决方案。再来看看 ChatRoom 吧,我们想周期性地回收旧数据。

复制代码
@javax.ejb.Singleton
public class ChatRoom {
private java.util.Map<User,Collection<String>> userComments;
@javax.ejb.Schedule(minute="1", hour="*")
public void cleanOutOldDataFromChatLogs() {
/** ... not reprinting all the existing code ... */
}
}

我们编写了一个方法来快速检查数据,如果必要的话就会删除旧的聊天记录,这样一切就尽在掌握之中,不会再出现内存吃紧的问题了。这里使用了声明式模型以保证方法每隔一小时都会运行,当然了,我们仍然从 EJB 3.0 中注入了 TimerService。

无接口的视图

EJB 3.0 中的 Bean 至少要实现一个接口(Local 或是 Remote 的业务接口),接口用作 Bean 对于客户端的视图。虽然间接地使用接口是个很强大的技术,但有时会使事情变得复杂。在 EJB 3.1 中可以编写没有接口的 Bean。客户端所看到的视图就是类所公开的 public 方法。

复制代码
@javax.ejb.Stateless
public class Calculator {
public float add ( float a , float b) {
return a + b;
}
public float subtract (float a , float b){
return a - b ;
}
}

该 Bean 的客户端可以通过正常的注入来获取 Bean 并调用其方法:

复制代码
@javax.ejb.EJB
private Calculator calculator;
...
float result = calculator.add( 10 , 10 ) ;
...

异步服务

处理可伸缩问题最简单的办法就是不去处理(直到容量不足时才考虑)!这种方式就是人尽皆知的 SEDA(staged event driven architecture)模式,可以通过排队来避免瓶颈的出现。通过这种方式为任务排队,同时客户端可以继续后面的处理。如果组件的处理需要花费很长时间,同时系统没有过载,那么这种模式可以保证处理时间较长的组件不会把系统搞糟。

处理可伸缩性问题的另一个方法就是不要在单向消息交换时阻塞客户端的调用。此外还可以进行异步的处理,让客户端继续后面的处理直到结果返回。所有这些方法都加到了 EJB 3.1 中新的异步服务支持当中。我们可以在 Bean 或是单个方法上使用注解 @javax.ejb.Asynchronous 以告诉容器在调用结果返回前不要阻塞客户端的执行,这样客户端就可以继续后续的处理,从理论上来说,这种方式可以让容器缓存待处理的任务直到其可以处理为止。

如果使用 @Asynchronous 来注解 Bean 类或是业务接口,那么该注解会应用到 Bean 上的所有方法;否则只有使用了 @Asynchronous 注解的方法才会变成异步的。异步方法可以返回 void 或是 java.util.concurrent.Future的实例。客户端可以通过 Future实例来查询返回的结果,但方法调用后客户端可以继续后续的处理而不会被阻塞。在这种方式下,即便 EJB 花费了 1、2 个小时的处理时间也无所谓,因为客户端并不会受到任何影响。从概念上来看,这与向 JMS 队列发送请求来调用服务的方式是一致的。

Future实例可用于取消任务或是等待结果。客户端的事务上下文不会被传播到异步方法中,这样对于异步方法来说,REQUIRED 要比 REQUIRES_NEW 更具效率。

看个具体的示例吧:要构建的服务需要与几个 Web Services 通信并综合使用调用的结果。我们需要结果,但却不能挂起客户端的请求(或许是个网页)。如下代码展示了该服务:p>

复制代码
@javax.ejb.Stateless
public CarHotelAndAirLineBookingServiceBean implements CarHotelAndAirLineBookingService {
@javax.ejb.Asynchronous
public Future<BookingConfirmation> bookCarHotelAndAirLine( Car rental, Hotel hotel, AirLine airLine) {
/** ... */
}
}

我们在客户端(一个 JSF action)这样调用服务:

复制代码
@Named
public BookingAction {
@javax.ejb.EJB private CarHotelAndAirLineBookingServiceBean bookingService;
private Future<BookingConfirmation> confirmation;
public String makeRequest(){
Hotel hotelSelection = ... ;
Car rentalSelection = ... ;
AirLine airLineSelection = ... ;
confirmation = bookingService.bookCarHotelAndAirLine(
rentalSelection, hotelSelection, airLineSelection ) ;
return "showConfirmationPending";
}
public Future<BookingConfirmation> getConfirmation(){ /* ... */ }
/* ... */
}

简化的部署

EJB 3.1 还首次提供了动态、更加简化的部署方式,支持.WAR 文件内的部署。在打包到 WEB-INF/classes 或是 WEB-INF/classes 下的.jar 文件中时,具有组件定义(component-defining)注解的类将成为 Enterprise Bean 组件。此外,还可以通过 WEB-INF/ejb-jar.xml 文件来定义 Enterprise Bean。打包到.WAR 中的 Bean 共享单独的命名空间并成为.WAR 环境的一部分。这样,将.jar 打包到 WEB-INF/lib 下就与将 class 文件放到 WEB-INF/classes 中是一样的了。

新规范另一个值得注意的特性就是 EJB Lite。对于很多应用来说,EJB 技术显得过于庞大了。EJB Lite 提供了 EJB 的一套子集,关注于 Session Bean 的使用。它提供了一种方式以嵌入式风格来使用 EJB 组件,这简化了单元测试。EJB Lite 支持无状态、有状态以及单例的 Session Bean。Bean 可以有 Local 接口,也可以没有接口。他们可以与拦截器协同工作并使用事务和安全等容器服务。

EJB 3.1 是个强大的开发者工具集,能满足应用 80% 的需要。规范的未来是光明的,同时也首次明确地提及了未来 Java SE 的裁剪机制将要移除的特性。未来可能会移除的特性包括老式的容器管理和 Bean 管理的持久化、Entity Bean 的 EJB 2.1 客户端视图、EJB QL(EJB 2.1 的查询语言)以及基于 JAX-RPC 的 Web Service 支持(包括 J2EE 1.4 引入的端点和客户端视图)。显然,EJB 3.1 是个引人注目、向后兼容的升级,它代表了 5 年前开始的 JSR 220(EJB 3.0)的新进展。

查看英文原文: Java EE6: EJB3.1 Is a Compelling Evolution

2010-02-17 07:256206
用户头像

发布了 88 篇内容, 共 270.8 次阅读, 收获喜欢 9 次。

关注

评论

发布
暂无评论
发现更多内容

深度学习基础入门篇[9.1]:卷积之标准卷积:卷积核/特征图/卷积计算、填充、感受视野、多通道输入输出、卷积优势和应用案例讲解

汀丶人工智能

人工智能 神经网络 深度学习 卷积网络 卷积相关算子

Seata 的可观测实践

阿里巴巴云原生

阿里云 云原生 seata

硬核!互联网资深大佬手码高并发编程速成笔记(2023版)限时开源

Java 并发编程 高并发

真香!阿里最新产出分布式进阶实战手册,涵盖分布式架构所有操作

Java你猿哥

架构 微服务架构 Spring Cloud Spring Boot ssm

Wallys miniPCIe wlan modules/ QCA9880 /2.4G&5G

Cindy-wallys

QCA9880

2023语言与智能技术竞赛开辟“双赛道”:寻找“全民测评官”,探索AI多模态能力

飞桨PaddlePaddle

【实践篇】领域驱动设计:DDD工程参考架构 | 京东云技术团队

京东科技开发者

领域驱动设计 DDD 企业号 5 月 PK 榜 工程架构

【程序员日记】——从业务编排到低代码 | 京东云技术团队

京东科技开发者

低代码 业务 企业号 5 月 PK 榜 业务编排

BSC智能链游戏链系统开发解析

Congge420

区块链追溯系统开发 元宇宙 元宇宙系统开发

深度学习基础入门篇[9.2]:卷积之1*1 卷积(残差网络)、2D/3D卷积、转置卷积数学推导、应用实例

汀丶人工智能

人工智能 神经网络 深度学习 卷积网络 卷积核

关于PCBA元器件布局的重要性

华秋PCB

工具 元器件 PCB 布局 PCB设计

看完这篇,DWS故障修复不再愁

华为云开发者联盟

数据库 后端 华为云 华为云开发者联盟 企业号 5 月 PK 榜

OpenHarmony社区运营报告(2023年4月)

OpenHarmony开发者

OpenHarmony

如何使用、部署 Auto-GPT?系统开发技术分析

Congge420

系统开发 区块链、 autogpt

进阶面试皆宜!阿里强推Java程序员进阶笔记,差距不止一点点

Java java面试 Java八股文 Java面试题 Java面试八股文

用写代码的方式画图-试下PlantUML吧 | 京东云技术团队

京东科技开发者

开发工具 PlantUML 画图软件 企业号 5 月 PK 榜

rt下降40%?程序并行优化六步法 | 京东云技术团队

京东科技开发者

性能优化 异步编程 企业号 5 月 PK 榜 多线程优化 并发框架

线上问题处理案例:出乎意料的数据库连接池 | 京东云技术团队

京东科技开发者

数据库 GC 线上问题 数据库连接池 企业号 5 月 PK 榜

软件测试/测试开发丨Python控制流–分支判断和循环

测试人

Python 软件测试 自动化测试 测试开发

刷爆LeetCode!字节技术官亲码算法面试进阶神技太香了

Java 数据结构 算法 LeetCode

为什么我们拥有庞大的语言模型,而Vision Transformers的规模却很小?

Baihai IDP

人工智能 深度学习 计算机视觉 白海科技 Vision Transformers

聊聊 万亿流量场景下的负载均衡实践

Java你猿哥

负载均衡 ssm 高并发 DNS 负载均衡架构

GitHub标星30k!基于Spring MVC Mybatis分布式开发系统-zheng项目(内附源码)

Java你猿哥

开源 架构设计 分布式架构 JavaEE zheng

面试官:你能和我说一下 CMS 垃圾回收器吗?

Java你猿哥

算法 CMS JVM 垃圾回收器 垃圾收集器

IPQ8072 or IPQ8072A with the QCN9074/9024 chipset / well-suited for high-end routers.

Cindy-wallys

IPQ8072

2023数字中国建设峰会:百度点石获开放群岛开源社区优秀共建单位

百度安全

LED显示屏如何做到节能

Dylan

效率 能源 节能 LED显示屏

火山引擎DataTester:小改动带来大收益,A/B实验助力幸福里APP精准优化

字节跳动数据平台

ab测试 A/B 测试

TF游戏Ai智能系统开发

Congge420

系统开发 区块链、 智能运维AIOps

Java EE 6:EJB 3.1的变化引人注目_Java_Josh Long_InfoQ精选文章