当前位置:七道奇文章资讯编程技术Java编程
日期:2011-01-26 02:54:00  来源:本站整理

JCA 1.5: 消息输入流[Java编程]

赞助商链接



  本文“JCA 1.5: 消息输入流[Java编程]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:

         EJB 2.0 消息驱动 bean

  在利用 J2EE 1.3 和 EJB 2.0 时,消息驱动 bean(MDB)只能起到相当有限的作用.它们让利用程序异步地接纳传送 JMS 目标的消息.而 MDB 需求实现 javax.jms.MessageListener,如清单 1 所示:

  清单 1. javax.jms.MessageListener 接口

1 public interface MessageListener {
2     void onMessage(Message message);
3 }

  MDB 还需求实现 MessageDrivenBean 接口.后果,典型的类看起来大概近似清单 2 中的 ExampleMdb :

  清单 2. 示例 EJB 2.0 MDB

1 public class ExampleMdb implements MessageDrivenBean, MessageListener {
2     public void ejbCreate() throws CreateException { ... }
3     public void ejbRemove() { ... }
4     public void setMessageDrivenContext(MessageDrivenContext ctx) { ... }
5     public void onMessage(Message message) {
6         if (msg instanceof TextMessage) {
7             String text = ((TextMessage) message).getText();
8             InitialContext context = new InitialContext();
9             ExampleHome home = (ExampleHome)context.lookup("java:comp/env/ejb/Example");
10             Example bean = home.create();
11             bean.operation(text);
12         }
13     }
14 }

  假如像清单 2 那样遵循 EJB 2.0 标准的倡议,那么 onMessage 办法负责抵消息的内容举行解包,然后调用其他 EJB 履行实际的业务逻辑.

  但是别曲解 —— EJB 2.0 MDB 当然有它们的好处.关于初学者来说,因为 MDB 不是由客户机调用的,所以不需求编写 home、remote 或 local 接口.并且 —— 最主要的一个好处就是,多个实例可以并行操作.在没有 MDB 时,利用程序大概已经肯定了一个异步接纳消息的目标,但是由于没有将工作复制到别的一个线程中的本领,所以利用程序须先处理第一个消息才能处理下一个消息.

  就像其他 EJB 那样,MDB 可以利用 bean 托管事件大概容器托管事件.后者对 MDB 有一些扭曲.首先,只答应利用两个事件属性:Required 和 NotSupported.这是完好公道的.因为没有客户机调用 MDB,没有需求担当的事件,所以要做的就是可以指出 bean 能否该当在事件中运行.第二,也是更重要的,假如指定了事件属性 Required,那么传送到 MDB 的消息就作为消息的一部份接纳.假若有什么事情出错,事件将回滚,那么消息将被重新放在目标上,再次举行处理.

  正如在清单 3 中可以看到的,MDB 只用于 JMS 的这个事实也反映在布置描写符中:

  清单 3. EJB 2.0 布置描写符

1 <ejb-jar>
2   <enterprise-beans>
3     <message-driven>
4       <ejb-name>Example MDB</ejb-name>
5       <ejb-class>example.ExampleMDB</ejb-class>
6       <transaction-type>Bean</transaction-type>
7       <acknowledge-mode>Auto-acknowledge</acknowledge-mode>
8       <message-driven-destination>
9         <destination-type>javax.jms.Topic</destination-type>
10         <subscription-durability>Durable</subscription-durability>
11       </message-driven-destination>
12       <message-selector>
13         JMSType = 'car' AND color = 'red'
14       </message-selector>
15     </message-driven>
16   </enterprise-beans>
17 </ejb-jar>
18

  在清单 3 中可以看到,布置描写符中的一些元素对应着 JMS 概念中的应答情势、定阅、长期性和消息挑选器.别的一个元素给出了消息目标的范例,它必须是 javax.jms.Queue 大概是 javax.jms.Topic.

1 public interface MessageListener {
2     Record onMessage(Record inputData)
3             throws ResourceException;
4 }

  CCI 接口展示了新的机动性的一些好处.首先,不需求把 MDB 传送给 JMS 消息.在清单 4 的接口中,传入一个 Record 对象.JMS 消息到达目标时也无需触发办法调用.关于 MDB 会在什么情形下驱动,JCA 标准没有做任何限制.它可以是资源适配器接纳到后端系统的一些外部刺激之后的后果,也可以仅仅是一些内部事件,乃至大概是由计时器驱动的事件.第二,如清单 4 所示,调用的办法也可以拥有返回参数.在这种情形下,便可以传送回第二个 Record 对象,正如清单 5 的 ExampleListener 接口中的第一个办法所示,范例无需相同:

  清单 5. listener 接口示例

1 public interface ExampleListener {
2     ExampleOutput process(ExampleInput input);
3     String getData();
4     void request(int id, ExampleRequest request);
5 }

  普通该当用办法的返回参数向造成办法调用事件的发动者供应呼应,不管它是资源适配器还是其他什么系统.但是,就像 ExampleListener 接口的第二个办法所表现的那样,实际上可以不用任何参数调用 MDB,只用它检索一些值.第三个办法表明:办法可以利用的参数个数没有限制.这意味着资源适配器可以把初始事件解析为将传送给 MDB 的多个值.可以看到,办法的参数可以是原生范例或是对象.最后,即便 ExampleListener 接口有多个办法,利用它也是精确的.这样便可以让资源适配器按照事件判断要调用哪个办法.

  既然 MDB 接口中消除了与 JMS 有关的限制,那么将布置描写符放在哪呢?清单 6 显示了一个 EJB 2.1 布置描写符示例,针对的是实现 ExampleListener 接口的 MDB:

  清单 6. EJB 2.1 布置描写符

1 <ejb-jar>
2   <enterprise-beans>
3     <message-driven>
4       <ejb-name>Example MDB</ejb-name>
5       <ejb-class>example.ExampleMdb</ejb-class>
6       <messaging-type>example.ExampleListener</messaging-type>
7       <transaction-type>Bean</transaction-type>
8       <activation-config>
9         <activation-config-property>
10           <activation-config-property-name>
11             HostName
12           </activation-config-property-name>
13           <activation-config-property-value>
14             example.com
15           </activation-config-property-value>
16         </activation-config-property>
17         <activation-config-property>
18           <activation-config-property-name>
19             DefaultId
20           </activation-config-property-name>
21           <activation-config-property-value>
22             2001
23           </activation-config-property-value>
24         </activation-config-property>
25       </activation-config>
26     </message-driven>
27   </enterprise-beans>
28 </ejb-jar>
29

  在清单 6 中可以看到,messaging-type 元素包含 MDB 实现的那些接口的类名.假如遗漏了这个元素,那么可以采取 javax.jms.MessageListener 的旧值.特定于 JMS 的元素已经被一组通用的名称-值对替换,这个名称-值对叫作 激活配置属性(activation-configuration properties).在清单 6 中可以看到,为 HostName 和 DefaultId 属性辨别指定了值 example.com 和 2001.

  可以编写实现肆意接口的 MDB,这听起来太棒了,感受不像是真的——但是它确切是真的.接下来的事大概就不太让人惊奇了:需求找到一个预备调用这个接口的资源适配器.资源适配器用它的布置描写符中的 messagelistener-type 元素表示它预备支持的接口(大概不止一个接口),如清单 7 所示:

  清单 7. 输入资源适配器的布置描写符

1 <connector>
2 <display-name>Example Inbound Resource Adapter</display-name>
3 <vendor-name>Example COM</vendor-name>
4 <eis-type>Example EIS</eis-type>
5 <resourceadapter-version>1.0</resourceadapter-version>
6 <resourceadapter>
7   <resourceadapter-class>
8    example.ExampleRaImpl
9   </resourceadapter-class>
10   <inbound-resourceadapter>
11    <messageadapter>
12     <messagelistener>
13      <messagelistener-type>example.ExampleListener</messagelistener-type>
14      <activationspec>
15       <activationspec-class>example.ExampleActivationSpecImpl</activationspec-class>
16       <required-config-property>
17        <config-property-name>HostName</config-property-name>
18       </required-config-property>
19       <required-config-property>
20        <config-property-name>PortNumber</config-property-name>
21       </required-config-property>
22      </activationspec>
23     </messagelistener>
24    </messageadapter>
25   </inbound-resourceadapter>
26 </resourceadapter>
27 </connector>
28

  具体看看这个示例布置描写符是值得的.它从一些传统的东西开始:显示名称、供应商名称、资源适配器衔接的企业信息系统(EIS)的名称,以及适配器的版本.这些内容背面随着一个 resourceadapter 元素,它的第一个子元素包含 ResourceAdapter 接口的适配器实现的名称.背面随着的是 inbound-resourceadapter 元素,它可以包含多个 messageadapter 实例.每个 messageadapter 实例都与一个 messagelistener-type 相关联.所以通过拥有多个 messageadapter 元素,可以编写一个输入资源适配器,支持多个接口.但是,必必要保证每个 messageadapter 指定一个差别的接口.

  每个 messageadapter 还包含实现 ActivationSpec 接口的类的名称.在下一节中,我将介绍若何用这个类包含每个布置的 MDB 的配置信息.

1 public interface ActivationSpec extends ResourceAdapterAssociation {
2     void validate() throws InvalidPropertyException;
3 }

  这个实现类遵守 JavaBean 尺度,可以通过得当指定的 getter 和 setter 办法来定义大量属性.在将 MDB 布置到利用服务器 style="COLOR: #000000" href="http://server.it168.com/" target=_blank>服务器中时,将利用这个类,以下所示:

  利用服务器通过查看 MDB 布置描写符中 messaging-type 元素的内容,判断 MDB 实现的接口.

  然后利用服务器找到支持这个接口的已经布置的资源适配器,挑选一个想在上面布置 MDB 的适配器.

  利用服务器成立 ActivationSpec 类的实例,这个类对应于选中的资源适配器和接口,然后利用内省(introspection)功效肯定类的属性以及默许值.

  用 ResourceAdapter 的父类上同名配置的属性覆盖默许值.

  可以挑选覆盖这些属性值中的任何值.

  然后这些属性被 MDB 布置描写符中的 activation-config 属性的值再次覆盖.

  利用服务器检测要求在资源适配器布置描写中指定的全部 bean 属性(在这个示例中,是 HostName 和 PortNumber)都有供应的值.

  可以看到,布置的 MDB 终究利用的属性可以来自很多地方,重要的是记着它们的先后次序.分外是要注意 MDB 的布置描写符不需求包含资源适配器要求的全部属性.

  一旦全部属性设置就绪,利用服务器便可以挑选调用 ActivationSpec 上的 validate 办法,大概把这个办法的调用推迟到利用程序启动时.资源适配器大概用这个办法查抄算术属性能否在可以承受的范围之内,大概确保表示列举值的字符串有效.资源适配器还该当查抄最后的属性集能否一致;比方,大概要按照其他属性的值来断定某个属性的值能否受限或是必须的.InvalidPropertyException 包含一项或多项检测失利时需求抛出的一组无效属性.

  成功的考证并不意味着布置的 MDB 必定能成功启动.资源适配器只能履行静态检测,也就是说,履行那些不需求衔接到后台系统的检测.只有当利用程序启动时,资源适配器才能考证近似于主机名称和端口号这样的属性能否精确.

  MDB 生命周期管理

  一旦成功地把包含 MDB 的利用程序布置到利用服务器中,下一步就是启动利用程序.利用服务器用清单 9 中的 ResourceAdapter 接口中的两个办法,向资源适配器告诉关于某个具体 MDB 生命周期的事件(在标准中称之为 端点):

  清单 9. ResourceAdapter 接口上的端点生命周期办法

1 public interface ResourceAdapter {
2     void endpointActivation(MessageEndpointFactory endpointFactory,
3             ActivationSpec spec) throws ResourceException;
4     void endpointDeactivation(MessageEndpointFactory endpointFactory,
5             ActivationSpec spec);
6     ...
7 }

  在启动利用程序时,要为每个布置的 MDB 调用一次 endpointActivation 办法.第一个参数(我将在下一节具体介绍)是一个成立端点实例的工厂类.办法的第二个参数是在前一节中配置的 ActivationSpec.假如从前没有做过,那么目前可以这样做,目前,资源适配器普通利用来自 ActivationSpec 的信息与后端系统成立某种情势的远程衔接.假如在做这项工作的历程中,资源适配器断定配置的信息不精确,那么它将抛出 NotSupportedException.

  注意,资源适配器不该当阻塞在这个办法中.一旦它肯定配置是精确的,则该当当即返回.假如需求举行进一步处理(比方为新的事件按期申请衔接),那么资源适配器该当利用 WorkManager 接口,把工作安置到别的一个线程上.

  在包含 MB 的利用程序被终止时,大概处在利用服务器的正常停机期间,会调用对应的 endpointDeactivation 办法.传送给这个办法的参数就是在 endpointActivation 上传送的同一个对象.实际上,因为 JCA 标准强迫要求,关于每个端点激活都要成立 MessageEndpointFactory 的一个新实例,所以在不活动(on deactivation)期间传送的对象可以用作在二者之间举行彼此关联的键.比方,在激活时成立的资源大概放在一个堵截与 MessageEndpointFactory 的接洽的映射中,然后在服务器不活动的时刻,再检索出这些资源,对它们举行清理.

  调用 MDB

  目前全部工作都已经就绪,到了资源适配器实际调用 MDB 的时刻了.在利用 J2EE 1.3 时,这一步大概将利用一个相当麻烦的利用服务器工具,该工具是 JMS 标准的一个构成部份.交互很复杂,并且在某些地方,交互的指定也很糟,从而造成差别的厂商用差别的方法对需求举行注释.幸运的是,JCA 标准不但让 MDB 可以实现任何接口,还极大地简化了这一历程中的事物.

  清单 10 显示了传送给 endpointActivation 办法的对象实现的 MessageEndpointFactory:

  清单 10. javax.resource.spi.endpoint.MessageEndpointFactory 接口

1 public interface MessageEndpointFactory {
2     boolean isDeliveryTransacted(Method method) throws NoSuchMethodException
3     MessageEndpoint createEndpoint(XAResource xaResource) throws UnavailableException;
4 }

  isDeliveryTransacted 办法让资源适配器判断关联的 MDB 能否运行在事件中调用指定办法.假如 MDB 正在利用容器托管的事件,并且要处理的办法具有 Required 事件属性,那么 isDeliveryTransacted 会返回 true .假如事件属性采取 NotSupported 答应的其他值,大概 MDB 正在利用 bean 托管的事件,则返回 false.

  我将在下一节中介绍事件.目前,假定 isDeliveryTransacted 返回了 false (大概假定资源适配器不支持事件).这意味着在调用 createEndpoint 办法时,可以把 null 作为 XAResource 的参数传入.这个办法返回一个实现了 MessageEndpoint 接口的对象,如清单 11 所示:

  清单 11. javax.resource.spi.endpoint.MessageEndpoint 接口

1 public interface MessageEndpoint {
2     void release();
3     void beforeDelivery(Method method)
4             throws NoSuchMethodException, ResourceException
5     void afterDelivery() throws ResourceException;
6 }

  返回的对象还实现了 MDB 在它的布置描写符中声明的接口.在最简单的情形下,资源适配器便可以把 MessageEndpoint 的范例转换成必要的接口,然后调用预期办法.

  createEndpoint 返回的对象明显不是利用程序开辟人员实现的类的实例,因为这个类没有实现 MessageEndpoint 接口.相反,它是利用服务器成立的一个代理.利用服务器大概利用了 Java 1.4 引入的动态代理支持,当即成立对象,它也大概在布置利用程序时就成立了必要的类.容器利用代理来包装实际的端点,以便供应事件和安全性这样的服务.这里对比一下代理和对无状况 bean 本地接口的引用.在利用会话 bean 的情形下,只能调用在本地接口中声明的办法.近似地,关于代理,也只能调用在 MDB 的布置描写符中声明的接口上的办法.

  资源适配器可以挑选保持在一个端点上,以便在后续调用中利用它.大概,资源适配器在完成任务并为下一调用成立另一个端点时,也可以调用 release.普通,利用服务器保持一个端点池,所以第二个选项大概是为了在多个线程之间供应更好的重用而供应的.

  我说过这代表的是简单情形.JCA 标准把这称作 Option A 消息传送.作为什么时刻需求可供替换的 Option B 消息传送的一个例子,可以将资源适配器想像为代表利用程序传输序列化的 Java 对象的消息传送系统的一部份.但愿调用的 MDB 办法采取反序列化之后的对象作为参数.糟糕的是,与序列化对象对应的类是 J2EE 程序程序的一部份,因此该类位于利用程序的类途径中,而不是位于资源适配器的类途径中.Option B 用 beforeDelivery 办法和 afterDelivery 办法圆满地办理了这个问题.调用 beforeDelivery 会提早履行一些容器操作(这些操作正常情形下大概是在调用代理和调用实际端点办法之间发生的).这些操作包含把利用程序的类加载器和线程关联起来.调用 beforeDelivery 之后,资源适配器便可以用线程适配器将对象反序列化,并把对象传送给 MDB 接口上要求的办法.

  容器知道自己已经履行了一些在这个端点代理上要求的操作,所以会在调用实际的 MDB 办法时跳过这些办法.但是,被调用的办法必须和 beforeDelivery 上传送的 Method 对象匹配,不然就会抛出 RuntimeException.在调用该办法之后,资源适配器必须调用 afterDelivery 来履行办法调用之后该当发生的对应的容器操作.比方,这样就答应适配器将办法返回的对象序列化,不过仍旧是通过利用利用程序的类加载器来实现的.

  图 1 显示了两个消息传送选项的并列式对比.

  图 1. 消息传送选项

  

  关于 Option A,可以看到前调用逻辑和后调用逻辑是作为一个办法调用的部份履行的,而关于 Option B,它们被脱离,辨别由 beforeDelivery 和 afterDelivery 驱动.

1 public interface ResourceAdapter {
2     XAResource[] getXAResources(ActivationSpec[] specs)
3             throws ResourceException;
4     ...
5 }

  利用服务器调用每个 XAResource 对象上的 recover 办法来肯定资源管理器预备好的事件.然后按照情形为每个事件调用 commit 或 rollback.

  在前文中,介绍了 ExecutionContext 若何与 WorkManager 结合,把事件导入利用服务器.假如用导入的事件调用具有事件属性 Required 的端点办法,那么这个办法将担当该事件.在这种情形下,任何 XAResource passed on createEndpoint 上传送的办法都不会列在该事件中.

  托管对象

  在最后一节中,我将介绍的一个主题是:可以平等地用于输入和输出 资源适配器,固然这一主题在 JCA 标准的消息输入流一章中层介绍过.标准的 1.5 版本的目标之一就是答应 JMS 供应者作为 JCA 资源适配器实现.假如理解 JMS,那么就会注意到它包含两类可以管理的对象:衔接工厂和目标.通过托管衔接工厂和它们在资源适配器的布置描写符中定义的属性,JCA 供应了一种机制,使管理员可以定义衔接工厂,以便布置的程序可以通过 Java 名称与目录服务接口(JNDI)查找它们.但是 JMS 目标不是工厂,而是拥有差别属性(描写它们表示的行列或主题)的对象.假如这样,那么怎么才能成立 JMS 目标呢?

  JCA 1.5 标准定义了托管对象 来补偿这个空白.资源适配器的布置描写符可以包含一个或多个 adminobject 元素,如清单 13 所示:

  清单 13. 显示托管对象的布置描写符代码段

1 <adminobject>
2    <adminobject-interface>example.ExampleAdminObject</adminobject-interface>
3    <adminobject-class>example.ExampleAdminObjectImpl</adminobject-class>
4    <config-property>
5     <config-property-name>Color</config-property-name>
6     <config-property-type>java.lang.String</config-property-type>
7      <config-property-value>Red</config-property-value>        
8    </config-property>
9    <config-property>
10     <config-property-name>Depth</config-property-name>
11     <config-property-type>java.lang.Integer</config-property-type>
12    </config-property>
13   </adminobject>
14

  在这种情形下,利用程序盼望从 JNDI (通过资源环境引用)查找实现了 example.ExampleAdminObject 接口的对象.布置描写符供应了能供应这个对象实现的 JavaBean 类的名称.它还供应了很多命名属性,每个属性都有一个范例和一个可选的默许值,这种方法非常近似于托管衔接工厂.当管理员但愿定义一个对象时,利用程序服务器的工具该当答应管理员挑选资源适配器和托管对象接口,然后提醒管理员输入每个属性的值.利用服务器随后将包含这个信息的引用绑定到 JNDI.当利用程序履行查找时,就成立一个托管对象的实例,并且在把对象返回利用程序之前设置好属性.

  目前该当可以看出 JCA 资源适配器若何通过利用托管对象来供应 JMS 目标对象了.但是请不要忘掉,您可以对任何想让管理员可以配置的 JavaBean(不但仅是衔接工厂)利用托管对象,这些 JavaBean 可以通过 JNDI 拜候.

  完毕语

  在本文中,我注释了消息驱动 bean 在 J2EE 1.3 和 J2EE 1.4 之间的改变,分外是目前若何实现任何接口.您已经看到若何用 JCA 消息输入流合约来配置资源适配器,以便用它来检索 MDB 实例以及调用 MDB 上的办法.我还具体介绍了调用 bean 办法的选项,以及调用事件性办法的意义.最后,我介绍了托管对象若何利用资源适配器定义将要配置的 JavaBean,并使其可以通过 JNDI 拜候.

  这一文章系列介绍了 JCA 1.5 的一些新特点,从优化和生命周期管理开始,到工作管理和事件,最后以消息输入流合约告终.像过去一样,标准供应了信息的肯定根源,并且必定会在将来的版本中持续发展.我但愿您认为这个系列有效,不管您是打算进级现有的资源适配器,还是打算重新编写一个新的资源适配器,大概仅仅把资源适配器用作利用程序的一部份.


  以上是“JCA 1.5: 消息输入流[Java编程]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
  • 通过JCA实现企业级操纵程序的"即插即用"
  • 在SpringSide 3 中操纵JCaptcha
  • JCA 1.5: 消息输入流
  • JCA 1.5: 优化和生命周期管理
  • 理解 JCA 事件
  • <b>为EAI挑选JCA、JMS或Web服务</b>
  • 本文地址: 与您的QQ/BBS好友分享!
    • 好的评价 如果您觉得此文章好,就请您
        0%(0)
    • 差的评价 如果您觉得此文章差,就请您
        0%(0)

    文章评论评论内容只代表网友观点,与本站立场无关!

       评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论
    Copyright © 2020-2022 www.xiamiku.com. All Rights Reserved .