看起来很美...解读EJB3.1规范
前言
2004年Rod Johnson以<j2ee development without EJB>为宣言, 吹响了声讨EJB的号角, 后来,J2EE世界的沉重腐朽的柏林墙被推翻,一个春天到来了,J2EE步入了轻量级时代,时至今日,5年过去了,投机贩子Rod Johnson和他鼓弄出来的spring具然成了所谓的事实上的开发标准,以及于,人家现在想变更一下子策略维护策略,跟商业挂点钩,就闹的轩然大波,(请参见kyo100900翻译的平衡的质疑:Spring维护策略的再次调整(完))。
然而,被spring以及webservice 等逼入绝境的EJB,挣扎着出了个3.0,还算打了个漂亮的绝对反击战,至少重拾了不少人对它的信心。
做为“以人为本”,讨好程序员的体现EJB3.0主要的变化有:
1.纳入Gavin King ,clone 了hibernate,出台JPA1.0规范,替代可笑的Entity bean。
2.不再强制EJB实现除业务接口外的其它接口,也不强制抛出异常。EJB变成了一个POJO。
3.简洁的annotation替代了冗长的xml配置文件,但是通过XML文件将可以对annotation进行覆盖,以保证可以灵活的进行配置。
4.Dependency injection.
但是,EJB这么多年实在是跟程序员积怨太深,大家总得千方百计的挑它的不是,哪能一下子就妥协大夸它的好呢,要知道程序员可都是很有骨气的。
于是,我们说EJB还是不够好,原因如下:
1.EJB,必须要在EJB容器中运行,而通常一个好的商用的带EJB容器的应用服务器的价格是不菲的。
2.EJB,运行依赖EJB容器,使得单元测试困难,不合现在agile develop,TDD的要求。
3.EJB容器的实现,是跟具体的厂商有关的,使得EJB在不同app server上的移植可能出现问题。
4.EJB使得使用某些设计模式变得困难,如singleton.
等等。。
总体起来的结论就是,大家的希望是让EJB变得更加“和霭可亲”,最好变成一个普通JAVA类一样,运行在普通的jvm上,进行开发测试,但又能享受传统容器所提供的强大的企业级服务。通俗点说就是,EJB应该是又能当“婊子”,让每个程序员都能很容易的上手,又能立“牌坊”让它有那么两下子在普通javabean中显得与众不同,另外,不花钱最好。
那没有办法了,既然广大群众有这个需求,做为老鸨的JCP就得努力去做啊,毕竟真的EJB死了对谁也没有好处,那么多卖“避孕用品”的(EJB容器厂商)还靠这个过日子呢。还有那么多家其它的妓院(泛指其它平台)还虎视眈眈呢。
于是,EJB3.1 规范起草中,而且不时(通常是以月为单位),在the server side 上放出点风,调调大家的胃口,还能美其名约:“收集群众意见!”,我就是被这个棍子上的胡萝卜,牵着鼻子看完了那一系列的文章,那么现在,我们也来总结一下,EJB3.1到底可能会带给我们什么。
注:在3.1规范没有出台之前,这些新特性不保证不会被修改。
你夸我简单,那么我就在简单点。
EJB2.1被人诟病的一个原因是太麻烦了。要写一个session bean 要写多少东西呢?
一个远程/本地的接口。
一个Home接口。
一个Session bean
通常是两个descriptor file ejb-jar.xml xxx-ejb-jar.xml.
而且,每个业务方法都要强制你抛出异常,其实是这样子的,有很多程序员一见要try catch 实际上内心是讨厌的,因为他具体也不清楚到底catch了应该怎么处理。SO。
到了3.0这个情况有变。简单了,只要写一个业务接口,一个实现类就OK了,还不强制你抛任何异常。也不用写配置文件。还面向接口编程,多cool.
代码如下。
声明一个远程接口
Java代码
@Remote
public interface SimpleSessionBeanRemote {
public void yourBusinessMethod();
}
@Remote
public interface SimpleSessionBeanRemote {
public void yourBusinessMethod();
}
实现类
Java代码
@Stateless
public class SimpleSessionBean implements SimpleSessionBeanRemote{
public void yourBusinessMethod() {
// do bussiness.
}
}
@Stateless
public class SimpleSessionBean implements SimpleSessionBeanRemote{
public void yourBusinessMethod() {
// do bussiness.
}
}
其实这个复杂度应该是在大家的接受范围内了,但是JCP还不满足,说,你们不是说EJB麻烦吗。我操,老子这回将简单进行到底,你们不是想要POJO吗,行,这回接口也省了。你们爱怎么玩怎么玩吧。
Java代码
@Stateless public class RegisterServiceBean {
@PersistenceContext
private EntityManager entityManager;
public void (User register) {
entityManager.persist(register);
}
}
@Stateless public class RegisterServiceBean {
@PersistenceContext
private EntityManager entityManager;
public void (User register) {
entityManager.persist(register);
}
}
个人认为这个比较多余,但凡是做项目,在不规范,接口其实也还是要写的,JCP这么做其实是表明,你看,EJB现在也可以就是个JAVA类,你写个Hello World 一样的java 类,它也可以是EJB,恩!java也在向.NET学习,模糊java bean 和EJB的界线,EJB是什么,EJB就是声明了企业级服务的普通java bean。
声明式的同步控制及singleton pattern
一个好消息,EJB3.1将会有单例模式的EJB,这应该是一种新的EJB类型。
你可能要问,这个有什么用,我们为什么要单例。当你的应用中有一些数据将被整个应用共享时,你不希望,这些资源被重复的获得,你希望将它们统一缓存在一个对象中,那么这个对象就应该是单例的,你可能要说,那很简单啊,单例,我写过,我还知道有两种模式,一种叫“懒汉式”,一种叫”饿汉式”,当然,如果你的应用是一个stand alone应用,这个是可以的,但当你的应用处于一个集群环境中这个就会有问题,也许你考虑,使用一些cache的中间件,如JBoss Cache, OSCache, JCS and SwarmCache,但这些总会给你的应用带来这样那样的额外的复杂度。
EJB3.1中将使用 @Singleton 标的bean来解决这个问题。(当然这个取决于具体厂商的实现)
示例代码如下:
Java代码
@Singleton
public class TransferFeeLevelBean {
@PersistenceContext
private EntityManager entityManager;
private FeeLevel feeLevel;
@PostConstruct
private void init() {
rate = entityManager.find(FeeLevel.class, new Integer(1));
}
public FeeLevel getFeeLevel() {
return feeLevel;
}
public void setFeeLevel(FeeLevel feeLevel) {
this.feeLevel = feeLevel;
}
}
@Singleton
public class TransferFeeLevelBean {
@PersistenceContext
private EntityManager entityManager;
private FeeLevel feeLevel;
@PostConstruct
private void init() {
rate = entityManager.find(FeeLevel.class, new Integer(1));
}
public FeeLevel getFeeLevel() {
return feeLevel;
}
public void setFeeLevel(FeeLevel feeLevel) {
this.feeLevel = feeLevel;
}
}
因为是单例的,所以一定要考虑并发的问题,默认情况下@Singleton标的bean中的所有方法都是线程安全,并支持事务的。
你也可以使用jdk1.5 中的concurrent一样的风格对这个bean进行声明式的线程控制。
Java代码
@Singleton
@ConcurrencyAttribute(READ_LOCK)
//读锁
public class TransferFeeLevelBean {
//..
//读写锁
@ConcurrencyAttribute(READ_WRITE_LOCK)
@Singleton
@ConcurrencyAttribute(READ_LOCK)
//读锁
public class TransferFeeLevelBean {
//..
//读写锁
@ConcurrencyAttribute(READ_WRITE_LOCK)
你甚至可以手工去控制同步。(类似事务的BMT)
Java代码
@Singleton
@ConcurrencyManagement(BEAN)
public class TransferFeeLevelBean {
@PersistenceContext
private EntityManager entityManager;
private FeeLevel feeLevel;
@PostConstruct
private void init() {
rate = entityManager.find(FeeLevel.class, new Integer(1));
}
Public synchronized FeeLevel getFeeLevel() {
return feeLevel;
}
public void setFeeLevel(FeeLevel feeLevel) {
this.feeLevel = feeLevel;
}
}
@Singleton
@ConcurrencyManagement(BEAN)
public class TransferFeeLevelBean {
@PersistenceContext
private EntityManager entityManager;
private FeeLevel feeLevel;
@PostConstruct
private void init() {
rate = entityManager.find(FeeLevel.class, new Integer(1));
}
Public synchronized FeeLevel getFeeLevel() {
return feeLevel;
}
public void setFeeLevel(FeeLevel feeLevel) {
this.feeLevel = feeLevel;
}
}
可以异步执行的session bean
企业级应用中,异步处理在某些场合上是必须的,比如你是一个企业网银的用户,你将进行一次几万笔的批量转帐,如果这个过程采用同步处理,你可能要等上十分钟的时间,这是用户无法忍受的,现实中,我们采用异步的方式进行处理,这个异步无论是用后台的job来跑也好,用JMS也罢,现在呢,其实我们也只是多了一种选择,而已。
3.1中,session bean将具备异步处理的能力,只要你在需要进行异步处理的方法上添加一个
@Asynchronous的标注。
如下
Java代码
@Stateless
public class BatchTransferProcessBean {
//..
@Asynchronous
public void processTransfer(List transDetail)
{ try{
process(transDetail);
//send message for success;
}catch(Exception)
{
//send message for fail;
}
}
//..
}
@Stateless
public class BatchTransferProcessBean {
//..
@Asynchronous
public void processTransfer(List transDetail)
{ try{
process(transDetail);
//send message for success;
}catch(Exception)
{
//send message for fail;
}
}
//..
}
当系统调用这个processTransfer方法时会马上返回,继续执行当前的调用。如果你还需要有返回值的话也是可以的,它采用的是jdk 1.5中的那个
Futher模式,当你调用方法的时候它将继续执行,当你想去取结果的时候,如果异步调用没有完成它会卡在那。(这个只是在JDK1.5中是这样子的,在ejb3.1中会不会也采用这个样子的偶好像也确定的来,应该也是由具然的容器商来决定的吧应该),如下。
Java代码
@Stateless
public class BatchTransferProcessBean {
//..
@Asynchronous
Public Future<Boolean> processTransfer(List transDetail)
@Stateless
public class BatchTransferProcessBean {
//..
@Asynchronous
Public Future<Boolean> processTransfer(List transDetail)
统一的JNDI命名
这个不用我说了吧,这个有在不同的服务器上布署EJB应用的人应该都有体会吧。
Weblogic上使用JNDI查找是
EJB名称#远程接口的全限定名
JBOSS好像是
Bean的名字/Remote(Local)
其它应用服务器没有用过,反正应该是每个每个都不一样,很是恶心。
因为这个,实际上EJB在不同服务器上是不可以无条件移殖的。现在JCP终于要对这个进行规范了,7UpCat是真的很高兴。。虽然这个不是什么太大的问题,不过每次学习写DEMO的时候偶的脑子总是不够用,又不舍得把时间浪费在记这些无聊的没有意义的东西上面。
这下子好了。
在J2SE上潜入EJB容器
当然首先要说明这个容器肯定不会很牛B,但我们也不要求它多牛B,只要能很方便的进行unit test那么我们已很高兴了,同志们,你是否想过,EJB可以跟普通的JAVA bean 一样在你的IDE中进行书写编译完成直接就可以运行进行测试呢?不用打包,不用布署,没有那该死的应用服务器,(我跟我老大统计过,基本上,在偶们的机子上跑一次weblogic要3.5分钟,约等于去烟室吸一支烟的时间).
你是否想过你的EJB以后也可以用Junit等工具类似如下代码进行测试呢?
Java代码
@RunWith(EmbeddableEJB3Runner.class)
public class PlaceBidTest {
@EJB
private PlaceBid placeBid;
@Test
public void testAddBid() {
placeBid.addBid(new Bid("rrahman", 10059, 200.50));
}
}
@RunWith(EmbeddableEJB3Runner.class)
public class PlaceBidTest {
@EJB
private PlaceBid placeBid;
@Test
public void testAddBid() {
placeBid.addBid(new Bid("rrahman", 10059, 200.50));
}
}
关于JSF
这个东西,我还没有玩过,所以不方便乱说话,有兴趣大家自己找来看看区别是啥。
Quartz 很伟大,那么EJB中的定时器,就应该和它一样伟大
标题在几年前,其实可以改成Hibernate 很伟大,那么Entity Bean就应该跟它一样伟大,于是现在的JPA变得跟hibernate一样伟大了。
Ejb3.0的Timer我基本没有用过,因为它确实不够强大,也不够灵活,在我看来支持Cron的Quartz简直是太方便了,在EJB3.1这一点也将有所改变。Timer将变得使用起来更简单,并且,时间设置更强大,它也将支持cron。
Java代码
@Stateless
public class SimpleJob implements {
@Schedule(second="0", minute="0", hour="0",
dayOfMonth="1", month="*", year="*")
public void sendEmail() {
... Code to generate the monthly news letter goes here...
}
}
@Stateless
public class SimpleJob implements {
@Schedule(second="0", minute="0", hour="0",
dayOfMonth="1", month="*", year="*")
public void sendEmail() {
... Code to generate the monthly news letter goes here...
}
}
@Schedule 标注很简捷以cron的方式进行声明执行的时间,简懂.估计以后会用得很多。
总结
当然,其它的新特性肯定还有很多,这里就不一一例举了,毕竟也都12点多了。
我们看了这些新特性发现,实际上以后EJB会向一个更加开放,更加简洁的方向发展,JCP努力的方向是这样,尽量保证EJB和普通是JAVA BEAN是一样的,然后通过声明来区分它们,这和.NET 中的思想是类似的。
一个普通的JAVA BEAN只要我进行了适当的声明,那么我也就是一个EJB了。
另一方面,现在JCP想尽量提供一个在本机可以使EJB运行起来的容器,最好是嵌入在JVM中,那么将大大提高EJB的开发效率。
一切看起来都很美,但最终出台以及容器厂商的实现以及广泛应用又要几年呢?
其实我认为spring 和EJB实际上本不是对立的,你用了EJB,项目中一样可以用SPRING ,毕竟SPRING 做为一个粘合剂还是很强大的。
另外,晚安,我亲爱的同行们,我们明天还要挻起胸膛去战斗呢.
00:20 浏览 (3485) 评论 (26) 分类: 技术前瞻 收藏 相关推荐 评论
[email protected] 2008-10-19 回复
iceboundrock 写道
[email protected] 写道
ejb失败了,就像.net败给java,没有根本上改变的话,是无法翻身的,显然无论是EJB还是.net都没有败,都在持续快速的向前演进。
我意思是相对而言,
.net的不跨平台,不开源,使得它虽然有很多优点,但是仍然有很大局限性,
ejb如此复杂,昂贵,也使得spring成为了事实上的标准;
iceboundrock 2008-10-18 回复
[email protected] 写道
ejb失败了,就像.net败给java,没有根本上改变的话,是无法翻身的,
显然无论是EJB还是.net都没有败,都在持续快速的向前演进。
[email protected] 2008-10-18 回复
ejb失败了,就像.net败给java,没有根本上改变的话,是无法翻身的,
terranhao 2008-10-17 回复
用3.0的人飘过,不用声明接口是太炫了
pig345 2008-10-17 回复
个人观点:
用家电作比喻的话
EJB就像原厂家电,希望能在一个黑盒子里面隐藏所有的细节
(事务/安全这些细节的事情花点钱买个容器帮你办),
只要告诉容器你的需求(事务/安全)就行了。
Spring就像DIY的电器,所有的线路板、零部件都给你提供了,你自己能组装成任何东西,全看你的能力大小!
代价是:不论你是作个简单放音喇叭,还是1000个频道的彩色电视,你都需要搞清楚80%以上的零部件的性能和所有线路板的原理。
ltian 2008-10-16 回复
看了EJB3.1规范的一些内容,尤其是分布式系统方面确为未企业开发提供了强大的支持,不知道什么时候可以发布EJB3.1,很想试试,希望楼主继续跟踪这方面的内容。及时发布最新的技术信息。
pancras 2008-10-15 回复
分析的深刻,尤其是比喻,升华该文
black_zerg 2008-10-15 回复
我还是蛮喜欢ejb3的,可惜除了jboss都不感冒
mht19840918 2008-10-15 回复
只要是存在就肯定有价值,所谓的好坏仅仅反映一种态度。
trackstone 2008-10-15 回复
4年前讨论的东西,现在我们仍然在讨论,,,可见sap工程师说中国的软件业落后世界10年是有一定的道理的
yushl 2008-10-15 回复
但是JCP还不满足,说,你们不是说EJB麻烦吗。我操,老子这回将简单进行到底,你们不是想要POJO吗,行,这回接口也省了。你们爱怎么玩怎么玩吧。
这句有个性,我喜欢!
murainwood 2008-10-15 回复
比Spring要看着舒服
java.hero 2008-10-15 回复
很好,其实说到底还是EJB能在庞大的系统中发挥其作用,中小型的现在普遍采用spring还是比较多的,各有千秋吧。
EXvision 2008-10-15 回复
那句“我操”,太销魂了,哈哈
luchajava 2008-10-15 回复
看了让人想跳楼妈妈的_________Orz
firefly.li 2008-10-14 回复
很黄很暴力的文章,喜欢!
与你同在 2008-10-14 回复
quote]
EJB应该是又能当“婊子”,让每个程序员都能很容易的上手,又能立“牌坊”让它有那么两下子在普通javabean中显得与众不同,另外,不花钱最好。
.......想到一起了。。。。。
rmn190 2008-10-14 回复
感谢楼主的好文!
EJB3.1介绍的这么全面,它的前世是EJB2.X那么繁琐,对手是Spring那么简洁,
引用
但是JCP还不满足,说,你们不是说EJB麻烦吗。我操,老子这回将简单进行到底,你们不是想要POJO吗,行,这回接口也省了。你们爱怎么玩怎么玩吧。
写的那么声情并茂,又特"色"显明,这不是"无韵之离骚"吗?
7upCat 2008-10-14 回复
多谢,jones同学提到的 关于JSF相关的新特性。
由于个人水平问题,以至于我不能全面的,阐述所有的新特性(比如JSF,SEAM,我都是没有亲自己使用过的).只希望不要"误人子弟"就好.
也希望大家能有更多的想法.
EJB也无非是种技术,所以不存在说是今天用spring明天就要用EJB什么的,而是,各自有自己适宜的场景.而且可以协同工作.
当然,EJB做为一种规范,使得,它跟具体的厂商的实现挂钧,一个好的实现会给企业应用大家带来多大的好处,显而易见,否则人家也绝不敢卖那么多钱.就这一点,依然决定了,它不能一下就平民化,这和买车是一个道理,如果你一个普通工薪阶层,没有特别的需求,买个"经济型,适用型"的车就好,还省油..
ugibb510 2008-10-14 回复
我又得用EJB了,习惯了spring,现在从新开始EJB。