??xml version="1.0" encoding="utf-8" standalone="yes"?>
Message-driven Bean是EJB2.0 规范中提出的的Enterprise Bean?/strong>
Message-driven Bean 的生原?/span>
效率原因
在JavaEE™q_中,客户端对Session Bean 和Entity Bean 的方法调用通过RMI或RMI-IIOP协议q行Q这是传l的通过|络q行q程调用的方法,当调用请求通过|络传播到容器,容器则将客户端请求变成一序列的方法调用依ơ进行。客L只有在容器处理完hq返回结果后方可l箋q行?/span>
可靠性的原因
当客L对Session Bean或Entity Beanq行调用Ӟ必须保证服务器容器处于运行状态,如容器或|络出现错误Q客L调用无法进行?/span>
事g的广?/span>
传统的RMI 或RMI-IIOP机制中,客户端在某一时刻只能与某一具体的服务器通讯Q?没有M内置的机制来事件广播到多个服务器?/span>
Message-driven Bean作ؓq程Ҏ调用的一U替代方法,在客L和服务器的直接方法调用之间放|了一个中间层Q接收一个或多个客户端的消息Qƈ消息{发给一个或多个消息的用?Message Consumer)?/span>
通过消息机制而非直接的方法调用,客户端可以l执行而不必等待服务器的运行结果,服务器可以选择在方法调用完成后通知客户Q而消息机制本w保证了信息传输的可靠性,同时使用消息?Message Domain)中的消息cd模型以达C件广播的机制?/span>
但是Q对Message-Driven Bean 的用也有一定的限制Q如不适用于依赖于Ҏ调用、要求具有明的q回值才能l的客户端程序。另外,如果在一个应用中q多的用了Message-Driven BeanQ?对应用的执行效率会产生影响Q所以不适用于对旉因素敏感的客LE序(如在下午两点定购下午四点的机,而在四点后才得到订购是否成功的结果,q时l果已毫无用??/span>
Message-driven Bean 作ؓ一般的JMS 使用?consumer)
作ؓ一U具有JMS使用?consumer)功能的Enterprise Beanlg模型QMessage-Driven Bean由EJB容器q行理Q具有一般的JMS使用?consumer)所不具有的优点Q如对于一个Message-driven BeanQ容器可创徏多个实例来处理大量的q发消息Q而一般的JMS使用?(consumer)开发时则必d此进行处理才能获得类似的功能。同时Message-Driven Bean可取得EJB所能获得的标准服务Q如容器理事务{服务?/span>
׃与Message-driven Bean相关的主?Topic)或队?Queue)可以在部|时配置Q因此,Message-driven Beanh更多的灵zL?/span>
但注意,一个Message-driven Bean在部|时只可与一个具体的主题(Topic)或队?Queue) 建立兌。如有多个主?Topic)或队列(QueueQ需要与一个Message-driven Bean兌Q则 可以在部|时部v多个Message-driven Beanc?或用一般的JMS使用?consumer) ?/span>
Message-driven Bean 与其他Enterprise Bean
作ؓEnterprise Beanlg模型之一QMessage-driven BeanQ具有一些与Session Bean 和Entity Bean相同的方法,但由于Message-driven Bean本n不处理客L调用Q也无会话状态,客户只能通过向与Message Driven Bean兌的队列或主题发送消息从而与Message-driven Bean q行交互Q因此,Message-driven Bean 与Session Bean 和Entity Bean之间最大的不同之处在于Message-Driven Bean不具有组件接口及Home接口?/span>
另外Q?/span>Message-driven Bean异步地处理队列(QueueQ或主题(Topic)中的消息Q而非Ҏ调用?/span>
Message-driven Bean
Message-driven Bean?/span>JMS消息驱动?/span>JavaEE™q_服务器端lgQ具备无状态、支持事务的特点。当?/span>JMS队列Q?/span>QueueQ或主题Q?/span>TopicQ中接收?/span>JMS消息后,由容器对lgq行调用。一般,可理解ؓ消息的监听器Q?/span>ListenerQ及接收者(ConsumerQ?/span>
Message-driven Beanlg对于客户端是不可见的。客L如希望调用封装在lg中的业务逻辑Q只能通过向组件监听的JMS队列Q?/span>QueueQ或主题Q?/span>TopicQ发送消息,然后容器以事件的形式向组件实例发送消息,lg实例Ҏ消息的内容调用相应的业务逻辑或其他组件?/span>
因此QQ何向lg监听的特?/span>JMS队列Q?/span>QueueQ或主题Q?/span>TopicQ发?/span>JMS消息的客LQ即可视?/span>Message-driven Bean的客L?/span>
Message-driven Beanlg模型不具备会话状态,也就是说Q当lg实例在没有对客户端的JMS消息提供处理的时候,所有的实例间没有差别?/span>
Message-driven Bean的运行和客户端的q行是异步的。同Ӟ对于客户端不可见。其实例由容器创建,其生存周期由容器控制?/span>
Message-driven Bean?/span>EJB容器、客L、消息系l?/span>
下图?/span>EJB容器、客L、消息系l与EJB之间的关p:
EJB容器、客L、消息系l与EJB之间的关p?/span>
客户端发送消息到JMS消息pȝ中的队列或主题?/span>Message-driven Bean在部|到容器中时Q指定的队列或主题,容器对其q行监听Q当容器从队列或主题中接收到消息之后Q将消息作ؓ事g的一部分通知容器中相应的Message-driven Bean实例?/span>
lg模型单元
Message-driven Bean由容器控制其生存周期Q容器提供安全、ƈ发、事务等{服务,对于客户端来_Message-driven Bean是不可见的。因此,Message-driven Bean不同?/span>Session Bean?/span>Entity BeanQ不hlg接口?/span>Home接口?/span>
Message-driven Beanlg模型包含两个单元Q即lgcd部v描述。下面分别对开发这些单元时Q涉及的普遍q程、规则及注意事项q行描述?/span>
EJB2.1规范中的Message-driven Beanlg中的lgcdd?/span>MessageDrivenBean接口?/span>EJB3.0规范不强?/span>Message-driven Bean实现该接口,而通过@MessageDriven注解q行标记q过依赖注入与注解实现类似功能?/span>
MessageDrivenBean接口中定义了两个容器理回调的方法:
· setMessageDrivenContextҎQ容器创?/span>Bean实例后,容器调用该Ҏ由容器l护?/span>Bean实例的上下文Q?/span>contextQ与Bean实例q行兌?/span>?/span>EJB3.0规范中,可?/span>@Resource注解通知容器注入MessageDrivenContext实例?/span>
· ejbRemoveҎQ在实例被容器清除时Q容器将调用此方法。一般,实例会在此方法中对实例占用的资源q行释放。在EJB3.0规范中,可?/span>@PreDestroy注解标记此方法?/span>
javax.jms.MessageListener接口
Message-driven Beanlg中的lgcdd?/span>MessageListener接口?/span>
在消息到?/span>Message-driven Bean指定的监听队列或主题Ӟ容器调?/span>javax.jms.MessageListener接口中定义的onMessageҎ。开发者在此方法中提供Ҏ息进行处理的业务逻辑?/span>
Session Bean?/span>Entity Bean不可实现javax.jms.MessageListener接口?/span>
javax.ejb.MessageDrivenContext接口
容器提供一?/span>MessageDrivenContext对象Q实例可以讉K由容器维护的实例的上下文环境。在此接口中Q定义了如下ҎQ?/span>
· getEJBHome?/span>getEJBLocalHomeҎQ从EJBContext接口l承的方法,Message-driven Bean实例不可调用此方法;
· getCallerPrincipalҎQ从EJBContext接口l承的方法,Message-driven Bean实例不可调用此方法;
· isCallerInRoleҎQ从EJBContext接口l承的方法,Message-driven Bean实例不可调用此方法;
· setRollbackOnlyҎQ当前事务将被永久标Cؓ回滚Q不会被提交。只有容器管理事务的Message-driven Bean可被允许使用此方法;
· getRollbackOnlyҎQ检查当前事务是否已被标Cؓ回滚。例如,EJB实例可以通过此方法,军_是否l箋在当前事务边界内l箋q行计算。只有容器管理事务的Message-driven Bean可被允许使用此方法;
· getUserTransactionҎQ返?/span>javax.transaction.UserTransaction接口?/span>EJB实例可通过此接口对事务边界q行划分Qƈ取得事务的状态。只有容器管理事务的Message-driven Bean可被允许使用此方法;
串行化的调用
Apusic应用服务器中?/span>EJB容器支持Message-driven Bean的多个实例的q发q行Q但是每个实例只“看到”一个串行的Ҏ调用q程Q因此开?/span>Message-driven BeanӞ不需要将其以可重入(reentrantQ的方式q行~写?/span>
消息处理的ƈ?/span>
Apusic应用服务器允?/span>Message-driven Bean的多个实例ƈ发执行,提供ҎQ?/span>StreamQ消息ƈ发处理?/span>
Message-driven BeanҎ的事务上下文
onMessageҎ在何U事务范围内被调用,取决于部|描qC指定的事物属性,?/span>Bean被指定用容器管理的事务的方式,则必d事务属性设|ؓ“Required”?/span>“NotSupported”?/span>
?/span>Bean采用Bean理的事务的方式Q即使用javax.transaction.UserTransaction接口q行事务划分ӞDBean实例被调用的消息接收操作q是事务中的一部分。如果希望消息接收操作是事务中的一部分Q则Bean必须使用容器理事务的方式,q且讄事务属性ؓ“Required”?/span>
消息接收认Q?/span>Message AcknowledgementQ?/span>
Message-driven Bean不能使用JMS API中提供的消息接收认操作。消息接收确认操作由容器自动完成。如Bean采用了容器管理事务的方式Q则消息接收认操作作ؓ事务提交的一部分自动q行。如使用?/span>Bean理事务的方式,消息接收认操作不能作ؓ事务提交的一部分Q开发者可通过在部|描qC?/span>acknowledge-mode元素指定消息接收认操作的方式ؓAUTO_ACKNOWLEDGE?/span>DUPS_OK_ACKNOWLEDGEQ如未指?/span>acknowledge-mode元素Q容器将使用AUTO_ACKNOWLEDGE方式q行消息接收认操作?/span>
指定队列Q?/span>QueueQ或主题Q?/span>TopicQ?/span>
?/span>Message-driven Bean被部|到容器Ӟ必须兌到某个消息队列(QueueQ或主题Q?/span>TopicQ,以便容器Ҏ队列或主题进行监听?/span>
开发者可通过@MessageDriven注解?/span>mappedName属性或部v描述文g中的message-driven-destination元素指定兌的队列或主题?/span>
?/span>Bean兌的是一个消息主题,则通过部v描述中的subscription-durability元素指定寚w列进行的是持久还是非持久订阅Q如此元素未指定Q则使用非持久订阅的方式?/span>
异常处理
Message-driven Bean中的onMessageҎ不能声明抛出java.rmi.RemoteException异常?/span>
一般来_Message-driven Bean在运行期间不应向容器抛出RuntimeException异常?/span>RuntimeException异常是指会导?/span>Message-driven Beanq入“不存?/span>”状态的非应用异常。如?/span>Bean使用?/span>Bean-managed事务q抛ZRuntimeException异常Q容器不应确认收Cq条消息?/span>
从发信端看来Q收信端一直存在,若发信端l箋对该目的地发送消息,容器会自动把消息转向到其?/span>Message-driven Bean实例?/span>
遗漏?/span>PreDestroy调用
在系l发生异常的情况下,不能保证容器M调用Bean?/span>PreDestroyҎQ因此,如果Bean?/span>PostConstructҎ中打开了一些资源,q在PreDestroyҎ中释放这些资源,在这U情况下Q则q些资源不能被释放?/span>
鉴于以上原因Q?/span>Message-driven Bean的应用需要提供一U机Ӟ以便周期性的清除q些未释攄资源占用?/span>
必须遵守的规?/span>
在开?/span>Message-driven BeanӞ开发者必遵守如下规则:
lgc?/span>
· 使用EJB2.1规范Ӟ必须间接或直接实?/span>javax.ejb.MessageDrivenBean接口Q?/span>使用EJB3.0规范Ӟ可改Z?/span>@MessageDriven注解对组件类q行标记?/span>
· 必须间接或直接实?/span>javax.jms.MessageListener接口Q?/span>
· cdd明ؓpublicQ不可被声明?/span>final?/span>abstractc;
· 必须拥有一个无参数?/span>public构造函敎ͼconstructorQ;
· cM能定?/span>finalize()ҎQ?/span>
· 在原EJB2.1规范中,cdd?/span>ejbCreate()Ҏ用来创徏lg实例Q在EJB3.0中,q一要求已被U除了?/span>EJB3.0的兼容规则规定,如果Message-driven BeancdCejbCreate()ҎQ将看作?/span>@PostConstruct注解标记的方法处理。此时若同时使用@PostConstruct注解Q则只能标记ejbCreate()Ҏ?/span>
onMessageҎ
· Ҏ必须被声明ؓpublicQ?/span>
· Ҏ不能被声明ؓfinal?/span>staticQ?/span>
· q回值必MؓvoidQ?/span>
· Ҏ只能有一?/span>javax.jms.Messagecd的参敎ͼ
· 不能抛出java.rmi.RemoteException异常
· q行期间一般来说不应抛?/span>RuntimeException。请参考:
ejbRemoveҎ
· Ҏ名必LejbRemove;
· Ҏ必须被声明ؓpublicQ?/span>
· Ҏ不能被声明ؓfinal?/span>staticQ?/span>
· q回值必MؓvoidQ?/span>
· Ҏ不能有参敎ͼ
· 不能抛出java.rmi.RemoteException异常?/span>
· ?/span>EJB3.0规范中,可?/span>@PreDestroy注解实现同样效果。若实现javax.ejb.MessageDrivenBean接口同时使用注解Q则只能?/span>ejbRemove()Ҏ注解?/span>@PreDestroy
生存周期
下图表示Message-driven Bean的生存周期?/span>
Message-driven Bean的生存周?/span>
包含处理企业数据的业务逻辑Q?/p>
EJB实例由容器在q行时创建及理Q?/p>
可在部v旉过~辑环境(environment entryQ定制EJB的行为;
EJB的各U服务设|信息,如事务及安全属性,从EJB的类文g中分d来。在部v和运行时Q可通过工具对EJB的服务设|信息进行管理;
EJB部v到EJB容器后,客户端才可通过EJB容器对EJBq行间接讉KQ?/p>
EJB可用Q何EJB规范中指定可以用的服务Q?/p>
EJB可以不经改动代码或重新编译,卛_直接装配C个新的应用中Q?/p>
当EJB被部|到不同的容器或服务器时QEJB开发者定义的客户视图(Client View)不会发生改变?/p>
事务处理Q?br /> 服务器提供对EJBlg的事务控制服务,多个业务操作同时成功Q或全部p|Q可以通过代码外的 部v描述来设|组件事务处理?Q?
EJB的客L有以下几U类型:
q行于相同容器或其他容器中的EJBQ?
一般的Javac,如Java应用E序、applet、servletQ?
非Java的客L境,如非Java语言~写的CORBA客户?/p>
一般,EJBlg׃下几个部分组成,即组件服务器 (Server)Q容?(Container)Q类 (Class) Q实?(Instance)
接口、Home接口QRemote 接口、Enterprise Beancd部v描述文g(Message-driven Bean不具有组件接口和Home接口Q。下面分别描q这些组成部?br />
EJB的组件接?br />
客户端通过EJB的组件接口访问EJB对象Q组件接口中定义了可被客L讉K的业务方?Message-driven Bean不具有组件接口)。组件接口分E接口和本地接口?/p>
EJB对象通过q程或本地接口,提供q程客户讉K或本地客戯问的支持?/p>
提供q程接口的EJB拥有可被q程客户讉K或本地客戯问的能力。对于提供了q程接口的对象,客户可通过标准的Java RMIQRemote Method InvocationQ进行远E对象调用?/p>
提供本地接口的EJB只可被本地组仉过本地接口q行调用。所谓本地组Ӟxq行于相同Java虚拟Z的本地EJB对象。本地调用通过一般的标准Java~程语言接口q行?/p>
EJB可以同时提供本地接口和远E接口,但一般只提供二者之一?/p>
HOME接口
EJB2.0规定了通过Home接口来提供客L创徏、清除和在同U类型的EJB中查扄定EJB对象的方?Message-driven Bean不包含Home接口Q。对于提供远E接口的EJBQ需要提供远EHome接口Q提供本地接口的EJBQ需要提供本地Home接口?/p>
Home接口由EJB开发h员编写,q程Home接口必须扩展QextendQjavax.ejb.EJBHome接口Q本地Home接口必须扩展QextendQjavax.ejb.EJBLocalHome接口?/p>
EJB客户端通过标准的JNDIQJava Naming and Directory Interface™QAPI定位Home接口?/p>
EJB3.0中,Home接口的功能由依赖注入以及可选的生命周期回调Ҏ实现。EJBlg不再需要提供Home接口
Enterprise Beanc?br /> Enterprise Beancd含了lg的实现细节?/p>
Enterprise BeancȝEJB开发h员编写,EJB2.0规范中的Enterprise BeanlgQ必d别声明实现如下接口,javax.ejb.SessionBean、javax.ejb.EntityBean和javax.ejb.MessageDrivenBean。符合EJB3.0规范的Enterprise Beanlg则不dC上接口,而用@Stateful、@Stateless、@MessageDriven注解标记EJBcR?/p>
部v描述文g
部v描述文g是用于包含Enterprise Bean的运行时属?安全性,事务性等{?信息的文Ӟ与以上部分一起Ş成完整的EJBlgQ通常部v描述文g使用囑Ş化的部v工具q行处理。在EJB3.0规范中,EJB部v描述文gq不是必ȝQ可以在代码中用注解来为EJBc附加部|信息。但部v描述文g可以令管理h员在部v时更为灵zREJB3.0规范规定Q当部v描述文g的信息与E序代码中的注解信息出现冲突Ӟ以部|描q文件ؓ准。这L理h员就可以通过修改部v描述文g来改变部|信息,而不重新编译应用程序?/p>
? 化的~程模型
x于业务逻辑实现QEJB 负责生命周期 (lifecycle), 数据存储 (persistence), 事务处理语义 (transactional semantic), 安全(security), ...
通用的编E模型:各种服务的高?API
Java 是其~程语言
EJB( 业务逻辑代码 ) 表示了与特定商业领域Q例如银行、零售等行业Q相适应的逻辑。它?br />
q行在业务逻辑层的 enterprise bean 处理?font color="#0000ff">一?enterprise bean 可以从客L接受数据Q对
它进行处理,q将其发送到企业信息pȝ层以作存储;同时它也可以从存储器获取数据Q?br />
处理后将其发送到客户端应用程?/font>?br />
有三U类型的 enterprise beansQsession beans、entity beans ?message-driven beans?br />
Session bean 描述了与客户端的一个短暂的会话。当客户端的执行完成后,session bean ?br />
它的数据都将消失Q与之相对应的是一?entity bean 描述了存储在数据库表中的一行持?br />
E_的数据,如果客户端终止或者服务结束,底层的服务会负责 entity bean 数据的存储?br />
Message-driven bean l合?session bean ?Java 信息服务QJMSQ信息监听者的功能Q它?br />
怸个商业组件异步地接受 JMS 消息?
?EJBlg模型的灵zL?/p>
EJBlg模型的灵zL表现在:
EJB可作C无状态服务的对象Q?
EJB可作C无状态服务的对象Q可通过向指定的消息队列或主题发送JMS消息Q以实现Ҏ对象的异步调用;
EJB可作CZ特定客户的会话对象。此cd象在客户q行跨越Ҏ的调用时Q自动维持会话状态;
EJB可作CZ务对象的实体对象Q在多个客户间共享;
EJB可作Z个细_度的持久对象,包含在一个粗_度业务对象的持久状态中?
通常Q被q程讉K的组件往往是粗_度的业务对象,如订单、雇员纪录;l粒度的业务对象往往不会采用可远E访问的EJBlg模型Q如订单中的采购V雇员纪录中的地址Q而是采用可本地访问的EJBlg模型或是作ؓEJB的附属类出现?/p>
?何时使用EJBlg:
下面是在使用EJBlg模型构徏企业应用Ӟ一些判断EJBlg模型是否适用的标准?br />
EJBlg是构建分布式企业应用的组件模型技术;
EJBlg规范是针对分布式企业应用制定的,是基于分布式对象技术的JavalgQEJBlg不涉及表C层的内容,因此Q必M其他表示层技术一起用;应用服务器提供了可以解决安全性、资源共享、持l运行、ƈ行处理、事务完整性等复杂问题的服务,从而简化了商业应用pȝ?br />
应用客户端类型的考虑Q?
一般,企业应用开发都会有多种cd的客L的需求,讉K相同的数据或业务逻辑。如使用Web客户提供对应用的ZInternet的访问,使用应用客户端提应用ZIntranet的访问。EJBlg模型业务逻辑与数据封装到EJBlg中,提供对多U客L的支持?/p>
应用数据与业务逻辑的ƈ发访问控制的考虑Q?
企业应用通常需要提供数据或业务逻辑的ƈ发访问能力,以此保证数据的完整性,׃EJB lg控制对后台数据的讉KQƈ理当前事务和数据库的内部锁定。节省了~写数据库控刉辑的工作量Q同时也保证了数据的一致性与正确性,从而降低了ȝE量?br />
全局事务控制的考虑Q?
企业应用通常需要对不同的资源进行事务性的操作Q如某个操作需要对数据库进行访问,同时可能需要通过JMS消息服务发送消息,或者,需要访问两个位于不同物理位|的异种数据库,q些操作必须在相同的事务环境中完成?br />
Z讉K控制的考虑Q?
企业应用中往往需要对某些资源q行讉K控制Q如需要针对不同用户对lgҎ调用讄讉K控制{略Q对讉K特定Web资源的用戯|访问控制策略等.