开发消息驱动的POJO

开发消息驱动的POJO

作者: Craig Walls,  出处:TheServerSide.com, 责任编辑: 叶江, 

2005-07-27 13:49

  消息驱动的POJO提供了类似MDB的功能,能够充分利用Spring中提供的功能,在当使用了Spring构架并用它来部署应用程序时完全成为了MDB的替代者。

为了准备下个月的演讲,我这段时间一直在补习关于消息驱动的POJO的知识。POJO的提出者是James Strachan,它通过ActiveMQ来部署和实现。

  消息驱动的POJO提供了类似MDB的功能,这点和简单的JavaBean类似。我发现消息驱动的POJO有一些引人注目的特性,完全成为了MDB的替代者,尤其是当你已经使用了Spring构架并用它来部署你的应用程序时。消息驱动的POJO能够充分利用Spring中提供的功能,例如AOP和Dependency Injection。

  尽管消息驱动的POJO并不是什么新鲜事物,但是我还是花了很大的力气才找到关于它的在线信息。ActiveMQ自己的文档不错,但是留给了我很多没有解决的问题。作为对那些搜索关于消息驱动POJO信息的人的帮助,我撰写了这篇文档,记录了我所学到的东西,我希望它能够起点作用,并能帮助你解决某些问题。

  你需要些什么:

  要开始POJO的开发或运行示例程序,你需要一些JAR包,下面是一个列表清单:

  activemq-core-3.1-SNAPSHOT.jar

  activemq-container-3.1-SNAPSHOT.jar

  activemq-ra-3.1-SNAPSHOT.jar

  commons-logging-1.0.3.jar

  concurrent-1.3.4.jar

  geronimo-spec-j2ee-connector-1.5-rc4.jar (or equivalentJ2EE JAR)

  geronimo-spec-j2ee-management-1.0-rc4.jar (or equivalentJ2EE JAR)

  geronimo-spec-jms-1.1-rc4.jar (or equivalent J2EE JAR)

  geronimo-spec-jta-1.0.1B-rc4.jar (or equivalent J2EE JAR)

  log4j-1.2.9.jar

  spring.jar (version 1.2.2)

 

在开发POJO的过程中,你将会遇到的最大难题是如何让这些JAR包一起工作。为了帮助你,我把所有你需要的东西都准备好了,包括一些示例程序,你可以点击此处进行下载。http://www.habuma.com/sia/mdpojo.zip

  开发消息驱动形式的POJO

  开发一个消息驱动的POJO和开发一个消息驱动的EJB并没有太大的不同。最大的区别就是你不用开发一个javax.ejb.MessageDrivenBean的实现,这意味着你也不必部署利用该接口来控制的EJB生命周期方法。(如果你需要在POJO的生命周期中使用hook,那么你可以在声明bean的时候使用Spring的init-method和destroy-method属性。)

  为了让读者的兴趣更多的集中在如何开发一个消息驱动的POJO上,我把示例程序写得尽可能地简单。按照所有的示例程序的惯例,这里是一个使用消息驱动的POJO的“Hello World”程序:

  package com.habuma.mdpojo;

  importjavax.jms.JMSException;
  import javax.jms.Message;
  import javax.jms.MessageListener;

  public class HelloBeanimplements MessageListener {
    public void onMessage(Message msg) {
      try {
        String name =msg.getStringProperty("name");
        if(name == null) {
          name ="World";
        }

       System.out.println("Hello " + name + "!");
      } catch (JMSException e) {
        // handle exception?
      }
    }
  }

  请注意到消息驱动的POJO必须实现一个javax.jms.MessageListener。尽管James Strachan将这个引用为POJO的一部分,我始终认为这不是一个纯的POJO,因为要让它正常工作,你必须实现一个平台/框架相关的接口。但是MessageListener接口并不会带来太多的系统消耗,而且也比MDB轻巧多了,所以我想我不能抱怨得太多。

  onMessage()方法很好理解,当一个消息被发送给这个bean时,系统就调用这个方法。在这个方法内部,我们从消息中获取了“name”属性,并用这个属性来显示传统的问候方式。

 

 

监听消息

  下一步要做的事是在Spring的框架中把HelloBean声明为一个bean并建立起它和一个消息队列的联系。声明bean本身是很简单的(在hello-mdpojo.xml中):

 <bean id="helloBean"class="com.habuma.mdpojo.HelloBean"/>   

  大家可以看到,这个bean里并无其他任何特殊之处。但是,在一个真正的应用程序中,你的消息驱动POJO可能会很复杂,可能被注入了对DAO的引用、服务层的bean或一些其他的用于协同工作的bean。此外,这个bean还可能以一些Spring框架内容作为代理,以满足声明日志、安全性等方面的需要。

  要建立起这个“helloBean”和一个消息队列的联系,我们需要使用ActiveMQ的JCAContainer。JCAContainer能够将自己与一个特定的ActiveMQ服务器连接起来,扮演Factory的角色,然后生成到该服务器的连接。在Spring中,它以的形式声明:  

 <bean id="activeMQContainer"class="org.activemq.jca.JCAContainer">
    <property name="workManager">
      <bean id="workManager"class="org.activemq.work.SpringWorkManager"/>
    </property>

   <property name="resourceAdapter">
      <bean id="activeMQResourceAdapter"
         class="org.activemq.ra.ActiveMQResourceAdapter">
        <propertyname="serverUrl" value="tcp://localhost:61616"/>
      </bean>
    </property>
  </bean>

  对于绝大多数的情况来说,这样的一份XML文档就足以建立起一个JCAContainer,并与消息队列发生互动。而好消息是,不管你有多少个POJO是消息驱动方式的,你只需要一个JCAContainer就可以了。

这里我们唯一需要关注的是赋予“serverUrl”属性和“activeMQResourceAdapter”内部bean的值。这个属性告诉容器如何连接到你的ActiveMQ服务器,在这个示例中,我们通过TCP的61616端口连接Localhost本地服务器。(61616是ActiveMQ默认的监听端口。)

  现在我们有了一个已经和ActiveMQ建立起联系的JCAContainer,并且也有了一个准备好接收消息的POJO,剩下要做的工作就是将POJO和JCAContainer连接起来了,下面的实现了这一操作:

 <bean id="HelloMDP"
      factory-method="addConnector"
      factory-bean="activeMQContainer">
    <property name="activationSpec">
      <beanclass="org.activemq.ra.ActiveMQActivationSpec">
        <propertyname="destination" value="Hello.Queue"/>
        <propertyname="destinationType" value="javax.jms.Queue"/>
      </bean>
    </property>
    <property name="ref"value="helloBean" />
  </bean>

  这个bean是关键的连接的代码。通过使用Spring的factory-method功能,这个bean的声明通过JCAContainer的addConnector()方法创建了一个到ActiveMQ服务器上“helloBean”的连接。特别地,“activationSpec”属性告诉JCAContainer创建一个连接并监听名字为“Hello.Queue”的消息队列,而“ref”属性则告诉JCAContainer将从该队列中获取的消息发送到一个叫做“helloBean”的bean中。

  先别急,要想让这个POJO正常工作还需要进行两个工作。

      第一,你必须启动你的ActiveMQ服务器,在ActiveMQ发布包的bin文件夹下,你能够找到一个activemq.bat(Windows版本)或activemq脚本(UNIX版本)文件,运行这个脚本能够启动一个ActiveMQ服务器的实例,并且在61616这个端口上进行监听。

 

 

第二,你需要一个简单的应用程序,来调用Spring的框架内容。下面的main()方法就足够了:

  publicstatic void main(String[] args)
  {
    newFileSystemXmlApplicationContext("hello-mdpojo.xml");
  }

  如果所做的一切都工作正常的话,那么此时应该有一个HelloBean POJO在等待处理一个消息了。现在就让我们来发送一条消息。

  发送一条消息

  用户可以使用很多种方法来发送一条JMS消息,但是为了我们这个例子的需要,我将使用Spring的JmsTemplate(在Spring in Action一书的第7章有描述)。下面关于JmsTemplate的声明是我用来测试HelloBean的代码(在mqclient.xml中):

 <bean id="jmsTemplate"
     class="org.springframework.jms.core.JmsTemplate">
    <property name="defaultDestinationName"value="Hello.Queue"/>
    <property name="connectionFactory"ref="connectionFactory"/>
  </bean>

  “defaultDestinationName”属性告诉这个模板所要附加的消息队列的名称。而“connectionFactory”属性则告诉模板如何去连接。我没有使用Spring的JndiObjectFactoryBean来从JNDI中创建一个connection factory,也没有使用任何javax.jms.ConnectionFactory的实现。但是对于这个简单的示例程序来说,我也不会错过JNDI,让我们来使用ActiveMQ的ActiveMQConnectionFactory:

 <beanid="connectionFactory"
     class="org.activemq.ActiveMQConnectionFactory">
    <property name="brokerURL"value="tcp://localhost:61616" />
  </bean>  

 

 

现在我们只须使用“jmsTemplate”bean来发送一个消息就可以了。在真正的应用程序中,你可能会把“jmsTemplate”注入到一个另外的bean的属性中来使用,但是为了简单性的考虑,我们只通过一个main()方法来直接访问这个bean:

  publicstatic void main(String[] args) {
    ApplicationContext ctx = new
       FileSystemXmlApplicationContext("mq-client.xml");

   JmsTemplate template = (JmsTemplate) ctx.getBean("jmsTemplate");
    template.send(
      new MessageCreator() {
        public Message createMessage(Sessionsession)
            throwsJMSException {
          MapMessage message =session.createMapMessage();
           message.setStringProperty("name", "Craig");
          return message;
        }
      }
    );
  }

  结论

  在另一个窗口中运行这个程序。如果所做的工作一切正常,那么你应该能够在运行JCAContainer应用程序的窗口中看到“Hello Craig!”的字符串,证明你刚才调用了一个消息驱动的POJO。

  那么结论是什么呢?为什么说消息驱动的POJO比MDB好呢?恩,我不会陈述任何关于消息驱动比MDB出色的地方,但是下面这些问题值得你去考虑和思索:

  MDB必须运行在EJB的容器中。由于应用程序的构架体系的原因,这一点有可能导致一些额外的花销,尤其是当你并没有使用任何EJB或并不需要一个EJB容器的所有功能的时候。从另一方面来说,消息驱动的POJO能够在任何地方运行,甚至能够在一个简单的main()方法中运行,它唯一所需要的就是一个ActiveMQ消息队列的支持。

  MDB需要你实现javax.ejb.MessageDrivenBean的生命周期方法。通常来说这样的生命周期方法并没有其他的用处,所以常常导致程序存在一些空的接口实现。虽然这并不是什么大问题,但是确实没有必要。

  尽管在上面的HelloBean这个简单的示例中没有体现出来,消息驱动的POJO确实能够充分利用Spring提供的对Dependency injection和AOP支持。简而言之,在一个Spring框架中,一个bean能够做什么,一个POJO就能够做什么。

  用于声明一个消息驱动的POJO的XML比用于声明MDB的XML更加紧凑。你应该记住,你只需要声明一个JCAContainer bean,而不管在你的应用程序中使用了多少个消息驱动的POJO。

  最后,有一件我还没有考虑过的事情,那就是EJB3 MDB和消息驱动的POJO的对比。说句实话,我实在没有时间去进行一次这样的比较,但是我希望能够尽快去做这件事情。如果你有关于这方面的任何建议,我很愿意倾听你的想法。

  消息驱动的POJO只是我在LoneStar 软件研讨论上演讲内容的一部分,该研讨会在下个月的Austin,TX举行,如果你住在Austin附近,我很希望能够在研讨会上看见你的到来。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值