- 浏览: 640294 次
- 性别:
- 来自: 北京
最新评论
-
2047699523:
java hibernate demo使用实例教程源代码下载: ...
hibernate延迟加载的原理与实现 -
在世界的中心呼喚愛:
hantsy 写道这种lazy的解释只对了一半,按java p ...
hibernate延迟加载的原理与实现 -
moguicy:
看了下时间,不是楼主是否还在开发
【翻译】Wicket启示录——理论与实践(一) -
xfan0828:
"最后但并不是最不重要的一点就是" BZ, ...
【翻译】深入浅出 EJB3.1(上) -
doudou87323:
十分感谢,正在学习中,受益匪浅
【翻译】深入浅出 EJB3.1(上)
终于有空将EJB3.1的最新文章与大家分享,原文请看:
http://www.theserverside.com/tt/articles/article.tss?l=EJB3-1Maturity
已经更新:【翻译】深入浅出 EJB3.1(下)
引言
Enterprise Java Beans( 简称 EJB) 是 Java Enterprise Edition( 简称 Java EE) 平台上的服务端组件架构模型,目标极力于快速并简化分布式,事务处理,安全以及便携式的应用程序。
EJB 在其 2.* 时代也叱诧风云过,由于能够解决许多企业应用程序的需求而被广泛采纳。但这只是 EJB 成功的表象,越来越多的质疑声开始抨击 EJB 的复杂。“缺乏好的持久层策略,又臭又长的布署描述符,能力有限的单元测试”等等这些常用却又不好用的技术导致了大量开发人员开始寻找新的“轮子”。
Sun 的反应的确有些迟钝,但还是它花费大量精力来修订规范,使得 EJB 得到很大的改观。 EJB3 摈弃了许多现有的缺点,呈现给开发人员的解决方案在社区中大受好评。 EJB 又一次变成了切实可行的解决方案,并且现在已经有许多放弃它的团队,再次接收 EJB 。
虽然它成功了,但 EJB3 还没有当初预计的那么理想。反观 EJB2.1 ,新规范要面对两个主要的挑战:
1. 为了改变 EJB2.1 现有的特性, ( 比如说需要强大的持久层框架来代替 Entity Beans ;支持使用 Annotation 来代替布署描述符;抛弃 home interface 等等。 ) ,需要进行大量的重建工作。
2. 为了引入新的解决方案,需要加入原先规范中没有的新技术。(比如说支持 Singletons ;支持方法拦截;支持异步调用;改进并增强现有的 Timer Service 特性 )
对于 EJB ,优先考虑的就是全部重建。“我们只有先清空杯子里的水,才能接纳新的东西”。现在杯子已经清空了,这对我们来说是非常有利的,而且还可以没有包袱的大胆前进。
EJB3.1 又一次引入了一系列新的特性,倾向于挖掘技术的潜力。依我来看, EJB3.1 绝对是一个重要的发布版本,它将那些长期让人渴望的特性带到开发者面前,更加能够满足最新的企业应用程序开发,同时对 EJB 再次被人们采纳将做出巨大的贡献。
近期, EJB 3.1 提议最终草案已经发布了,现在我们已经非常接近最终发行版了。本文会贯穿大多数新的特性,对每一个新特性都有会有一定程度的介绍。
No-Interface View( 非接口视图 )
EJB3.1 引入了 no-interface view 的概念——将一个 bean 的所有的 public method 通过一个 Local View 暴露出来。 ( 具体访问可见参见本文后面的 Global JNDI names ) Session Beans 并不强迫你再去实现任何接口。 EJB 容器提供一个指向 no-interface view 的引用实现,允许客户端调用该 bean 的任何 public method ,并且 no-interface view 也可以确保事务,安全以及拦截的行为与原先的用法一致。
通过 non-interface view ,所有 bean 的 public method( 当然也包括定义在其父类上的 public method) 都是可用的。一个客户端可以通过依赖注入或 JNDI lookup 得到该 view 的引用,用起来感觉就好像它是 local 或 remote 的 view 一样。
但与 local 和 remote 的 view 不同的是, local 和 remote 的 view 必须与其所实现的的业务接口同时存在 ,而 no-interface view 的引用则只是 bean 这个类本身。注意, no-interface view 不再依赖于接口 。
下面的代码样例说明了一个 servlet 使用 no-interface view 是一件多么容易事啊。这个被引用的 no-interface view 叫作 ByeEJB ,其实就是一个普普通通的 JavaBean 。该 EJB 并未实现任何接口,也没有提供什么多余的布署描述符。最后但并不是最不重要的一点就是,这里 EJB 引用的获得使用了依赖注入进行简化。
ByeServlet (...) @EJB private ByeEJB byeEJB; public String sayBye() { StringBuilder sb = new StringBuilder(); sb.append("<html><head>"); sb.append("<title>ByeBye</title>"); sb.append("</head><body>"); sb.append("<h1>" + byeEJB.sayBye() + "</h1>"); sb.append("</body></html>"); return sb.toString(); } (...) ByeEJB @Stateless public class ByeEJB { public String sayBye() { return "Bye!"; } }
实际上如果引用类型为 java 类而不是接口的话,还是有些硬性的限制条件:
l 客户端永远无法使用 new 操作符来获得引用。 ( 很明显如果是你自己 new 出来的, EJB 容器自然无法托管 )
l 除了 public method 外,如果其它方法如果出错,也会抛出 EJBException 异常。
l 一个指向该 view 的引用可以作为任何本地接口或其它 no-interface view 方法的参数进行传递或返回。
如果 bean 没有暴露任何 local 或 remote view ,则容器必须默认提供一个可用的 no-interface view 。如果 bean 提供了至少一个 local 或 remote view ,则窗口不会提供 no-interface view( 除非使用 @LocalBean 显式要求提供 ).
Bean 和其父类的所有 public method 都会通过 no-interface view 被暴露出来。这也意味着任何 public callback method 也会暴露出来,因此在使用的时候要注意这一点。
本特性避免了接口的编写,简化了程序的开发(实际上并不是所有的类都需要接口)。也许在不久的将来还会加入 remote no-interface view 。
Singleton
大多数的应用程序都有过至少需要一个 singleton bean( 对每个应用程序来说,它意味着只需要初始化一次 ) 的经历。许多供应商已经满足了这方面的需求,通过使用描述布署符来限定一个 bean 所允许的最大实例数量。供应商这种“各自为政”的方式破坏了 JAVA 到处宣扬的“一次编写,到处布署”的口号,因此迫切的再推出一套类似特性的规范来很有必要。 EJB 3.1 最终还是引入了 singleton session beans 。
现在主流的 session beans 有三类—— stateless , stateful 和 singleton 。 Singleton session beans 可通过使用 Singleton Annotation 来标注,然后每个应用程序会确保只实例化一次。 Singleton session beans 支持与客户端共享,当然也支持并发访问 ( 后面有会具体谈到 ) 。
singleton bean 的生命周期始于容器下列任意初始化阶段:
1. 直接实例化某个 singleton
2. 通过依赖注入实例化某个 singleton ,这样其依赖的那些 singleton 也会被跟着实例化,如此递推下去。
3. 通过执行 PostConstruct 回调
缺省情况下,容器有义务决定 singleton bean 何时被创建 ( 比如在 spring 中,默认是将所有的 singleton 在启动时就初始化 ) ,但是也允许开发人员使用 Startup annotation 在应用程序启动时,要求容器去对 singleton 进行初始化。此外, Startup annotation 还允许你去定义 singleton beans 之间的依赖关系。当容器开始处理任何客户端发过来的请示时,所有标注有 startup 的 singletons 都必须初始化完成。
下面的代码样例大致演示了依赖是如何实现的。 singleton A 的没有使用 @Startup 也没有别的 singleton 依赖于它,于是 A 的实例化由容器来决定 ( 说白了,此时 A 的实例化由具体 EJB 实现来决定,规范没有硬性规定 ) 。 singleton B 在应用程序启动过程中被实例化,但必须早于 singleton D 和 singleton E( 很明显,没有 B 的实例, C 和 D 可能都无法正常初始化 ) 。即使这个时候的 B 没有使用 @Startup ,但由于有其它的 singletons 依赖于它,它还是要先实例化的。 singleton C 由于使用了 @Startup ,它会在应用程序启动过程中被实例化,但必须比 singleton E 先完成。同理 D 也必须在 E 之前完成实例化。因此, E 是应用程序中会最后一个被初始化。 ( 注意,再重申一下 A 是否会初始化与供应商的实现有关,也许供应商的实现是预先加载,也许是延迟加载,但当你真正使用 A 的时候,肯定会保证被初始化了 。 )
@Singleton
public class A { (...) }
@Singleton
public class B { (...) }
@Startup
public class C { (...) }
@Startup(DependsOn="B")
@Singleton
public class D { (...) }
@Startup(DependsOn=({"C", "D"})
@Singleton
public class E { (...) }
有一点需要注意的是,如果一个 bean 依赖于多个 bean 的注入,那么这些被依赖的 beans 之间的初始化时机是不确定的。 E 依赖于 C 和 D ,并没有说 C 一定要在 D 之前被实例化,除非 D 本身也是依赖于 C 的。
singleton 可以 @Startup 定义依赖于现存其它模块中的 singletons 。
当应用程序关闭时,容器有义务执行 singletons 的 PreDestory 回调,将所有的 singletons 全部销毁。这个时候,启动时候的依赖关系在销毁时变得有意义了,比如说 A 依赖于 B ,当 A 被销毁时, B 还是存活的,刚好与初始化相反。
Singleton bean 会维护服务端与客户端调用而产生的状态,但当应用程序关闭或容器挂掉时,该状态并不会保存下来。 ( 大家一定想到这种情况如果使用序列化机制将状态保存下来,然后当程序再次启动时,再反序列化还原状态也是一种选择。不过,至于你 singleton 中装的是什么内容,是否需要被序列化,是否可以被序列化对容器来说还是未知数,所以干脆挂就挂吧。 ) 为了处理服务端与客户端的并发调用问题,开发人员必须定义一个并发策略。规范中定义了两种方式:
l CMC(Container-managed concurrency 容器托管的并发机制 ) :顾名思义,由容器来管理该 bean 实例的并发调用。这也是 EJB 的默认策略。
l BMC(Bean-managed concurrency Bean 托管的并发机制 ) :容器此时并不会干涉该 bean 实例的并发,把并发的同步调用推回给开发人员。 BMC 允许使用合法的同步原语(如 synchronized 和 volatile 关键字),来协调不同客户端不同线程对同一个 singleton 的并发访问。
( 呵呵,这不正是声明式与编程式的又一次实践吗 ? )
大多数情况下, CMC 肯定是首选。容器的管理并发问题时,还是使用“ Lock ( 锁 ) ”。每个方法都关联上一个 read lock 和 write lock 。 Read lock 表示应该方法可以尽可能的被多个线程并发调用,而 write lock 表示该方法在每次只能每一个线程访问。
缺省情况下, lock 的属性值是 write 。当然你可以通过使用 @Lock 来修改默认属性值。 @Lock 可以用于类,接口和方法。如其它 Annotation 类似, @Lock 也有继承性。在类级别使用 @Lock ,它的所有相关方法也会被应用上,除非你单独限制某一个具体的方法。
当某个方法持有 write lock 时,容器只允许其中一个并发线程去调用该方法。其它线程并必须等待,直到该方法再次变得可用。客户端的等待也许是无限期的,这个时候可以使用 @ AccessTimeout 来指定一个最大等待时间。如果超时了,会抛出 ConcurrentAccessTimeoutException 异常。
下面的代码示例中演示了如果使用 CMC 。 Singleton A 明确指定为 CMC( 尽管这么没有必要,因为默认就是 CMC ,主要还是为了演示 ) 。 Singleton B 并未定义任何并发策略,但按照规范,它还是属性 CMC 范畴,它的所有方法显示指定 CMC 使用 write lock 方式。 Singleton C 与 Singleton B 几乎一模一样,只是使用的是 read lock 方式。 Singleton D 和 Singleton C 一样,但是 D 中的 sayBye 方法重新定义为 write lock 。 Singleton E 总要是演示 @AccessTimeout 的使用,当有因等待 E 中某方法而被阻塞的客户端超过 10 秒时,就会招出 ConcurrentAccessTimeoutException 异常。
@Singleton @ConcurrencyManagement(CONTAINER) public class A { (...) } @Singleton @Lock(WRITE) public class B { (...) } @Singleton @Lock(READ) public class C { (...) } @Singleton @Lock(READ) public class D { (...) @Lock(WRITE) public String sayBye() { (...) } (...) } @Singleton @AccessTimeout(10000) public class E { (...) }
如果是在集群环境下,当应用程序布署在不同的 JVM 上,则每个 JVM 都有该 singleton 的一个实例。
直到 EJB 3 ,任何由 EJB 抛出系统异常都会导致实例被废弃和销毁。但这个原则并不适用于 singleton beans ——它们必须一直存活下来,至少应用程关闭时才销毁。因此任何在业务对像方法或回调抛出系统异常时,业务对象并不会被销毁。
与 stateless beans 一样, singletons 也可以暴露成 web services 。
Asynchronous Invocations( 异步调用 )
Session beans 方法的异步调用是这些新特性中最重要的特性之一。它可以应用于所有类型的 session beans 。规范规定:在容器开始执行某个 bean 实例的调用之前,异步调用的控制权一定要返回给客户端。这又将 session beans 提高到了一个崭新的高度——使有潜在异步调用需求开发人员从 session beans 中获得更多好处,也允许客户端触发并行处理的流程。
通过使用 @ Asynchronous 就可以将一个类或方法标记为异步调用。下面的示例演示了该 annotation 不同场合下的应用。 Bean A 将其所有方法标注为异步; Singleton B 中,只有定义的 flushBye 方法才是异步的;对 stateless C 而言,所有的通过 local interface Clocal 接口调用的方法都是异步的;而通过 Cremote 接口调用却是同步的。因此,同一个方法还可能由于所引用的不同接口而表现出不同的行为。最后, bean D 的 flushBye 肯定是异步的,于 Dlocal 是否是不是异步已经无关了。
@Stateless @Asynchronous public class A { (...) } @Singleton public class B { (...) @Asynchronous public void flushBye() { (...) } (...) } @Stateless public class C implements CLocal, CRemote { public void flushBye() { (...) } } @Local @Asynchronous public interface CLocal { public void flushBye(); } @Remote public interface CRemote { public void flushBye(); } @Stateless public class D implements DLocal { (...) } @Local public interface DLocal { (...) @Asynchronous public void flushBye(); (...) }
注意异步方法调用的返回类型必须是 void 或 Future<V> (其中 V 表示返回值的类型)。如果方法的返回值为 void ,则不允许声明任何应用程序异常。
Future 接口在 Java 5 中就被引入,提供四个主要方法:
- cancel(boolean mayInterruptIfRunning) :尝试取消异步方法的执行。如果某个 bean 的实例方法还未开始调用,容器会尝试取消这个调用。如果为参数为 true:执行中的任务可以被interrupt;如果参数为false:允许这个任务执行完毕 。标志位“ mayInterruptIfRunning ”用于控制目标 bean 是否对客户端是否可见,免得该异步调用被客户端不小心给取消了。
- get :当方法调用完成时,返回结果。该 get 方法有两个重载版本,一个是调用后一直处于阻塞状态,直到方法调用完成;另一个则可以设置一个超时的参数。
- isCancelled :指示该方法是否被取消。
- isDone :指示该方法是否执行完成。
规范要求容器提供 AsyncResult<V> 类作为 Future<V> 接口的实现,它可以将执行后的返回结构作为构造函数的参数,请看下面代码:
@Asynchronous public Future<String> sayBye() { String bye = executeLongQuery(); return new AsyncResult<String>(bye); }
Future<V> 的返回类型因不同的客户端角度而异。因此,如果在一个标有 @Asynchronous
接口中定义了方法 m ,那么请注意,只有这个接口中的方法允许返回类型为 Future<V> ,在其它别的非异步接口中的定义中不能带有 Future<V> ,只能返回普通的 V (注意 V 在这里表示的是泛型 )。请看下面示例:
@Stateless public class ByeEJB implements ByeLocal, ByeRemote { public String sayBye() { (...) } } @Local @Asynchronous public interface sayBye { public Future<String> flushBye(); } @Remote public interface ByeRemote { public String sayBye(); }
SessionContext 接口有一个 wasCancelCalled 方法,用于判断客户端是否调用了 Future 和 cancel 方法。如果 Future 的 cancel 方法的 mayInterruptIfRunning 参数设置为 true ,那么 wasCancelCalled 自然也会返回 true ,也就是说异步调用被终止了。(也就是说 SessionContext 可以用于判断某个异步方法是否被取消,提高程序的健壮性 )。请看代码示例:
@Resource SessionContext ctx; @Asynchronous public Future<String> sayBye() { String bye = executeFirstLongQuery(); if (!ctx.wasCancelCalled()){ bye += executeSecondLongQuery(); } return new AsyncResult<String>(bye); }
( 下面代码似乎有笔误,根本无法通过编译 )
如果异步方法抛出了一个普通应用程序异常,则这个异常传播到客户端时必须为 ExecutionException 。原始的异常信息仍然可以通过调用 getCause 来获得的。
@Stateless public class ByeEJB implements ByeLocal { public String sayBye() throws MyException { throw new MyException(); } } @Local @Asynchronous public interface ByeLocal { public Future<String> sayBye(); } //Client @Stateless public class ClientEJB { @EJB ByeLocal byeEjb; public void invokeSayBye() { try { Future<String> futStr = byeEjb.sayBye(); } catch(ExecutionException ee) { String originalMsg = ee.getCause().getMessage(); System.out.println("Original error message:" + originalMsg); } } }
对于异步方法的执行,客户端的事务上下文并不会传播到。因此,当下列异步事务方法调用时,可以得到的结论分别为:
- 如果方法 m 的事务属性定义为“ REQUIRED ”,那么它的表现形式将永远为“ REQUIRES_NEW ”。
- 如果方法 m 的事务属性定义为“ MANDATORY ”,那么它的表现形式永远是抛出 TransactionRequiredException 异常。
- 如果方法 m 的事务属性定义为“ SUPPORTS ”,那么它的表现形式永远是不会参与在事务上下文中。
对安全性的传播的也是同理。
-----------------------------------------------------------
文章有点长,后续部分会很快发出。 接下的内容包括:Global JNDI naming,Timer Service,EJB Lite,Simplified EJB Packaging,Embeddable EJB Containers等等。
评论
不过一看这么长,就知道BZ辛苦了,
发表评论
-
【翻译】深入浅出 EJB3.1(下)
2009-05-07 23:37 8935Global JNDI names( 统一的 全局 ... -
【翻译】Java EE 6体系结构的变革
2009-02-09 10:01 4532又看到 Reza 同学为 -
【翻译】Java EE 6体系结构的变革(完)
2009-02-09 10:00 6477JSF 2.0 尽 ... -
垃圾收集器是一个“宝贝收藏家”?
2008-11-25 23:58 3082原文请看:http://java.dzone.com/ar ... -
深入理解JBoss Cache3.0——Naga
2008-11-12 09:12 9748原文请看: http://java.dzone.com/ ... -
【翻译】Rod Johnson——关于当选JCP执行委员会的之言片语
2008-11-03 10:42 3194SpringSource 在上月底被宣布被加入 JCP ... -
【翻译】EJB3.1真的来了吗?EJB3.1系列文章(五) 终章
2008-10-16 14:37 9255历时9 个多月的EJB3.1 系列文章终于要划上圆满的句 ... -
【翻译】Rod Johnson——平衡的质疑:Spring维护策略的再次调整(完)
2008-10-09 09:33 4085不管你承不承认,Spring实际上已经是实事上JAVA企业开 ... -
【云计算专家Joseph Ottinger系列】应用服务器本质论
2008-09-08 08:58 3483原文请看: http://www.t ... -
Spring破坏了JEE规范吗?
2008-09-02 13:33 4097[TTS 编辑注:这是 TTS 论坛上的原帖。我现在把它 ... -
【翻译】spring配置全书(下)——附PDF完整版下载
2008-07-14 12:30 10847JMS 命名空间简介 Schema URI ... -
【翻译】spring配置全书(上)
2008-07-07 23:11 8958作者简介: Craig Walls 是 Texa ... -
【翻译】EJB3.1真的来了吗?EJB3.1系列文章(四)
2008-06-18 23:10 38224前言 Raza 同学终于又出 EJB3.1 文章了 ... -
【翻译】Rod Johnson——Spring的宣言:开源,开放(完)
2008-06-10 16:51 5622前言 这是本文的第二部分,里面提到并回答许多Spring用 ... -
【翻译】Rod Johnson——Spring的宣言:开源,开放
2008-06-06 13:06 6124原文地址: http://blog.sp ... -
【翻译】EJB3.1真的来了吗?EJB3.1系列文章(三)
2008-05-01 13:53 8849文本继续和大家分享EJB3.1特性,今天谈到的EJB Lite ... -
【Danny hui】运用抽象工厂模式自己动手写一个IoC
2008-04-23 16:34 6364本文的作者Danny hui似乎是TTS上的新人,我从Goog ... -
【翻译】Wicket启示录——理论与实践(三)完
2008-04-11 01:09 6298接下来,我们再看看EditContact类,把新建联系人的话和 ... -
【翻译】Wicket启示录——理论与实践(二)
2008-04-09 23:47 5892第二部分 实践 Application(应用程序) 与 ... -
【翻译】Wicket启示录——理论与实践(一)
2008-04-09 23:15 6816序 Wicket,当多数人看到它时,也许又是带着惯性思考 “j ...
相关推荐
### EJB 3.1 深入浅出 #### 一、EJB 3.1 的背景与改进 **EJB(Enterprise Java Beans)**是Java Enterprise Edition(Java EE)平台上的服务端组件架构模型,它旨在快速并简化分布式、事务处理、安全性以及可移植...
总的来说,《EJB 3.1 Cookbook》这本书深入浅出地讲解了如何利用EJB 3.1版本来构建高效、可靠的企业级应用,是Java EE开发者的重要参考资料。通过阅读这本书,开发者可以掌握EJB的核心概念、设计模式以及最佳实践,...
《EJB 3.0从入门到精通》是一本针对企业级Java开发者的教程,它深入浅出地介绍了EJB(Enterprise JavaBeans)3.0规范。EJB是Java EE(Java Platform, Enterprise Edition)平台的核心组件之一,主要用于构建可扩展、...
2.13.2 BeanShell在jBPM中的用法........63 第 3 章 流程节点详解.....................................67 3.1 公共属性...................................................68 3.2 Node节点........................
### EJB3中文版知识点概览 #### 一、EJB3.0概念与环境配置 **1.1 ENTERPRISE JAVA BEANS (EJB)** Enterprise JavaBeans(EJB)是Java...通过实践和深入理解这些知识点,开发者可以构建出稳定、高效的企业级应用。
2.13.2 BeanShell在jBPM中的用法........63 第 3 章 流程节点详解.....................................67 3.1 公共属性...................................................68 3.2 Node节点........................
该书通过深入浅出的方式,引导读者掌握Java EE 6平台的核心概念和技术,同时利用GlassFish 3服务器进行实践。源代码提供了书中示例项目的实际实现,帮助读者更好地理解和应用所学知识。 1. **Java EE 6概述**:Java...
这本书深入浅出地讲解了Spring 3.x版本的各个方面,旨在帮助读者掌握如何利用Spring高效地构建Java EE应用程序。 首先,Spring框架的核心特性之一是依赖注入(Dependency Injection,DI),它使得组件之间的耦合度...
资源中提到的《Spring 3.0就这么简单》这本书,很可能是针对Spring 3.0这一版本深入浅出的教程,涵盖了Spring 3.0的主要特性和使用方法,适合初学者和有经验的开发者阅读,以更好地理解和利用Spring 3.0框架的能力。...
这本书深入浅出地介绍了如何利用Spring框架构建高质量的企业级应用。Spring框架是Java EE开发中的核心组件,它简化了依赖注入、事务管理、数据访问以及Web应用的开发工作。 在第三版中,作者Craig Walls详细阐述了...
《求精要诀——Java EE编程开发案例精讲》是一本深入浅出的教程,旨在帮助读者掌握Java EE(企业版)的编程技术。PPT形式的教程通常以清晰直观的方式呈现复杂的概念,便于学习和理解。这个压缩包包含了一系列章节的...
《求精要诀——JavaEE编程开发案例精讲》是一本深入浅出的JavaEE编程教程,由清华大学出版社出版。本书旨在通过丰富的实例讲解,帮助读者掌握JavaEE平台上的核心开发技术,提升实际项目开发能力。书中源代码的提供,...
4. **EJB 3.1**:EJB(Enterprise JavaBeans)的最新版本,支持更高级的会话bean功能和消息驱动bean。 5. **JSF 2.0**:JavaServer Faces的更新版本,简化了UI组件的开发和使用。 6. **RESTful Web Services**:通过...
这本书结合了jbpm3.1的中文文档,为读者提供了深入浅出的指导。 首先,我们要理解JBPM的核心概念。JBPM提供了一个基于模型驱动的方法来定义和管理业务流程,通过 BPMN(Business Process Model and Notation)2.0 ...