`
guilin20
  • 浏览: 10282 次
  • 性别: Icon_minigender_1
  • 来自: 上海
最近访客 更多访客>>
社区版块
存档分类
最新评论

在Spring中使用ActiveMQ发送邮件

    博客分类:
  • java
阅读更多
转自http://dev.ymeng.net/spring-activemq-mail.html

项目的后台要求在更改密码后发送邮件通知用户,为了避免发送邮件时程序对用户操作的阻塞,之前中文版中使用了线程来发送邮件,而在英文版中,我决定使用JMS来异步发送邮件,让用户更改密码的操作和发送邮件的操作更进一步解耦,也在实际环境中试试JMS。

  我们的环境是Spring 2.5, Tomcat 5.5,使用ActiveMQ来实现JMS传送和接收。

  首先,我们在Spring中加入ActiveMQ Broker的配置:


     <bean id="broker"
        class="org.apache.activemq.xbean.BrokerFactoryBean">
        <property name="config"
            value="classpath:activemq.xml" />
        <property name="start"
            value="true" />
    </bean>

  我们在此处配置了BrokerFactoryBean,此Bean实现在Spring中配置嵌入式Broker,并且支持XBean方式的配置。Broker的配置文件由config属性指定,此处定义配置文件位于classpath中的activemq.xml。


  接下来我们需要创建Broker的配置文件activemq.xml。其实我们不需要从头配置,展开ActiveMQ的jar包,在org.apache.activemq.xbean下,就有一个activemq.xml,我们将其拷贝到WEB-INF/classes/目录下,并进行修改。

下面是activemq.xml的内容:


<beans>
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />

    <broker useJmx="false"
        persistent="false"
        xmlns="http://activemq.apache.org/schema/core">

        <transportconnectors>
            <transportconnector uri="tcp://localhost:61636" />
        </transportconnectors>

        <networkconnectors></networkconnectors>
    </broker>
</beans>

  在broker中,我们指定了不开启JMX,并且不使用持久化(persistent=”false”)。
  如果不对消息进行持久化存储,在容器或者JVM关闭、重启,或者崩溃后,所有的消息都将丢失,在我们的业务中,对于发送密码更改通知邮件,并非是重要的功能,所以我们选择不使用持久化存储,但对于不同业务逻辑,可能会需要进行持久化存储。ActiveMQ提供的持久化存储方案可以将消息存储到文件系统、数据库等。

  要在Broker中开启持久化存储,需要设置persistent为true,并且对其子节点persistenceAdapter, journaledJDBC进行配置。ActiveMQ jar包中的activemq.xml有被注释掉的示例,可以参考。

  接着我们在Spring中配置JMS Connection Factory。


     <bean id="jmsFactory"
        class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL"
            value="tcp://localhost:61636" />
    </bean>

  注意其中的borkerURL,应该是你在activemq.xml中transportconnector节点的uri属性,这表示JMS Server的监听地址。

  配置消息发送目的地:


     <bean id="topicDestination"
        class="org.apache.activemq.command.ActiveMQTopic">
        <constructor -arg value="MY.topic" />
    </bean>

    <bean id="queueDestination"
        class="org.apache.activemq.command.ActiveMQQueue">
        <constructor -arg value="MY.queue" />
    </bean>

  在JMS中,目的地有两种:主题(topic)和队列(queue)。两者的区别是:当一个主题目的地中被放入了一个消息后,所有的订阅者都会收到通知;而对于队列,仅有一个“订阅者”会收到这个消息,队列中的消息一旦被处理,就不会存在于队列中。显然,对于邮件发送程序来说,使用队列才是正确的选择,而使用主题时,可能会发送多封相同的邮件。
  Topic和Queue只是JMS内部以及其处理方式的不同,对于消息发送方和接收方来说,完全没有代码上的区别。

  配置Spring中消息发送的JMS Template:


     <bean id="producerJmsTemplate"
        class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory">
            <bean class="org.springframework.jms.connection.SingleConnectionFactory">
                <property name="targetConnectionFactory"
                    ref="jmsFactory" />
            </bean>
        </property>
        <property name="defaultDestination"
            ref="queueDestination" />
        <property name="messageConverter"
            ref="userMessageConverter" />
    </bean>

  注意此处的defaultDestination使用的是基于Queue的目的地。

  在实际的消息发送中,邮件内容需要用到User.username, User.password, User.email, User.fullname,显示如果我们直接发送User对象到消息队列,接收的时候也能直接取出User对象,那么在邮件发送程序中操作就会方便许多,所以在些处,我们定义了messageConverter属性,他指定了发送消息时使用的消息转换bean,这样,在直接发送User到JMS队列时,Spring会自动帮我们进行转换,下面是Converter的配置和代码:


     <bean id="userMessageConverter"
        class="com.tiandinet.jms.sample.UserMessageConverter" />

  此转换器同样也会使用在消息接收中,将接收到的消息转换为User对象。


package com.tiandinet.jms.sample;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.ObjectMessage;
import javax.jms.Session;

import org.apache.activemq.command.ActiveMQObjectMessage;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jms.support.converter.MessageConverter;

import com.tiandinet.jms.sample.User;

/**
* Converte User message.
*
* @author Yangtze
*/
public class UserMessageConverter implements MessageConverter {

    private static transient Log logger = LogFactory.getLog(UserMessageConverter.class);

    /**
     * {@inheritDoc}
     *
     * @see org.springframework.jms.support.converter.MessageConverter
     * #fromMessage(javax.jms.Message)
     */
    public Object fromMessage(Message message) throws JMSException {
        if (logger.isDebugEnabled()) {
            logger.debug("Receive JMS message: " + message);
        }

        if (message instanceof ObjectMessage) {
            ObjectMessage oMsg = (ObjectMessage) message;

            if (oMsg instanceof ActiveMQObjectMessage) {
                ActiveMQObjectMessage aMsg = (ActiveMQObjectMessage) oMsg;

                try {
                    User user = (User) aMsg.getObject();

                    return user;
                } catch (Exception e) {
                    logger.error("Message:[" + message + "] is not a instance of User.");
                    throw new JMSException("Message:[" + message + "] is not a instance of User.");
                }
            } else {
                logger.error("Message:[" + message + "] is not "
    + "a instance of ActiveMQObjectMessage[User].");
                throw new JMSException("Message:[" + message + "] is not "
    + "a instance of ActiveMQObjectMessage[User].");
            }
        } else {
            logger.error("Message:[" + message + "] is not a instance of ObjectMessage.");
            throw new JMSException("Message:[" + message + "] is not a instance of ObjectMessage.");
        }
    }

    /**
     * {@inheritDoc}
     *
     * @see org.springframework.jms.support.converter.MessageConverter#toMessage(java.lang.Object,
     *      javax.jms.Session)
     */
    public Message toMessage(Object obj, Session session) throws JMSException {
        if (logger.isDebugEnabled()) {
            logger.debug("Convert User object to JMS message: " + obj);
        }

        if (obj instanceof User) {
            ActiveMQObjectMessage msg = (ActiveMQObjectMessage) session.createObjectMessage();
            msg.setObject((User) obj);

            return msg;
        } else {
            logger.error("Object:[" + obj + "] is not a instance of User.");
            throw new JMSException("Object:[" + obj + "] is not a instance of User.");
        }
    }
}

  此程序实现了MessageConverter接口,并实现其中的fromMessage和toMessage方法,分别实现转换接收到的消息为User对象和转换User对象到消息。
我们在程序中使用的是ActiveMQObjectMessage,它是ActiveMQ中对javax.jms.ObjectMessage的一个实现。

  此时,我们已经完成了JMS Connection Factory和用于发送JMS消息的JMS Template配置,接下来,应该编写发送消息的Bean了,代码如下:

package com.tiandinet.jms.sample;

import org.springframework.jms.core.JmsTemplate;

import com.tiandinet.jms.sample.User;

/**
* Send user's login information mail via JMS.
*
* @author Yangtze
*/
public class UserMessageProducerImpl implements IUserMessageProducer {

    private JmsTemplate jmsTemplate;

    /**
     * {@inheritDoc}
     *
     * @see com.tiandinet.jms.sample.IUserMessageProducer
     * #sendUserLoginInformationMail(com.tiandinet.jms.sample.User)
     */
    public void sendUserLoginInformationMail(User user) {
        getJmsTemplate().convertAndSend(user);
    }

    /**
     * Return the jmsTemplate.
     *
     * @return the jmsTemplate
     */
    public final JmsTemplate getJmsTemplate() {
        return jmsTemplate;
    }

    /**
     * Set the jmsTemplate.
     *
     * @param jmsTemplate
     *            the jmsTemplate to set
     */
    public final void setJmsTemplate(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

}

  代码很简单,sendUserLoginInformationMail方法是唯一我们需要编写的,调用JMSTemplate的convertAndSend方法,Spring会自己调用我们之前配置的converter来转换我们发送的User对象。
  将此Java在Spring中进行配置,然后在Controller中进行调用即可实现发送User对象到JMS。

  到此为止,我们已经实现了消息的发送,现在我们来实现消息的接收。

  相对于发送,消息的接收的配置要相对简短些,我们使用MDP(Message Drive POJO)来实现消息的异步接收。我们需要实现javax.jms.MessageListener接口的void onMessage(Message message)方法来接收消息。不过我们可以使用Spring中提供的MessageListenerAdapter来简化接收消息的代码。
  我们先写处理消息的接口和实现类:

package com.tiandinet.jms.sample;

import javax.jms.JMSException;
import javax.jms.ObjectMessage;

import com.tiandinet.jms.sample.User;

/**
* JMS message handler.
*
* Yangtze
*/
public interface IMessageConsumer {

    /**
     * Handle the user message.
     *
     * @param user
     *            User
     * @throws JMSException
     *             exception
     */
    void handleMessage(User user) throws JMSException;
}
package com.tiandinet.jms.sample;

import javax.jms.JMSException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.tiandinet.jms.sample.User;
import com.tiandinet.jms.sample.IMailService;

/**
* JMS message handler - for User Message.
*
* Yangtze
*/
public class UserMessageConsumerImpl implements IMessageConsumer {

    private static transient Log logger = LogFactory.getLog(UserMessageConsumerImpl.class);

    private IMailService mailService;

    /**
     * {@inheritDoc}
     *
     * @see com.tiandinet.jms.sample.IMessageConsumer
* #handleMessage(com.tiandinet.jms.sample.User)
     */
    public void handleMessage(User user) throws JMSException {
        if (logger.isDebugEnabled()) {
            logger.debug("Receive a User object from ActiveMQ: " + user.toString());
        }

        mailService.sendUserLoginInforMail(user);
    }

}

  配置message listener

     <bean id="messageListener"
        class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
        <constructor -arg>
            <bean class="com.tiandinet.jms.sample.UserMessageConsumerImpl">
                <property name="mailService"
                    ref="mailService" />
            </bean>
        </constructor>
        <property name="defaultListenerMethod"
            value="handleMessage" />
        <property name="messageConverter"
            ref="userMessageConverter" />
    </bean>

  其中的mailService即是我们的邮件发送类,其sendUserLoginInforMail方法实现了邮件发送的功能。
消息侦听适配器defaultListenerMethod属性指定Spring在收到消息后调用的方法,此处为handleMessage,Spring会根据收到的消息User对象,调用handleMessage(User user)方法。

  配置消息侦听容器,并指定我们定义的消息侦听器。

     <bean id="listenerContainer"
        class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="concurrentConsumers"
            value="5" />
        <property name="connectionFactory"
            ref="jmsFactory" />
        <property name="destination"
            ref="queueDestination" />
        <property name="messageListener"
            ref="messageListener" />
    </bean>
分享到:
评论
4 楼 tzb2008 2008-11-03  
按照上面的配置我UserMessageProducerImpl里面的jmsTemplate怎么为null呢,郁闷啊
3 楼 tiandinet 2008-09-07  
呵呵,地址是 http://dev.ymeng.net/spring-activemq-mail.html

2 楼 guilin20 2008-09-05  
不好意思,兄弟,我也是从网上搜到你的,你把你的原创地址给我,我给你加上
1 楼 tiandinet 2008-09-02  
老兄,转偶的文章,也要给个出处嘛

相关推荐

    spring整合Activemq源码

    - **配置ActiveMQ**:在Spring应用中,我们需要添加ActiveMQ的相关依赖,并在配置文件中定义ConnectionFactory和Destination。ConnectionFactory是连接到消息代理的工厂,Destination则是消息的目标,可以是Queue或...

    ActiveMQ与Spring整合之异步发送邮件

    1. **邮件服务**:在Spring中,可以使用`JavaMailSender`接口来发送邮件,结合`SimpleMailMessage`对象定义邮件内容。 2. **异步处理**:通过集成ActiveMQ,可以创建一个消息生产者,将发送邮件的任务作为一个消息...

    ActiveMq+SpringMVC实现邮件异步发送

    在本项目中,ActiveMQ与SpringMVC框架结合,实现了邮件的异步发送功能。 首先,我们需要理解ActiveMQ的基本概念。ActiveMQ是Apache软件基金会的产品,遵循JMS(Java消息服务)规范,支持多种协议,并且可以跨平台...

    SpringBoot整合ActiveMQ(消息中间件)实现邮件发送功能

    在本项目中,"SpringBoot整合ActiveMQ(消息中间件)实现邮件发送功能"是一个典型的企业级应用示例,它展示了如何将SpringBoot框架与Apache ActiveMQ集成,以实现基于消息队列的邮件发送服务。下面我们将详细探讨这个...

    activeMQ+spring+springmvc整合示例

    在IT行业中,集成ActiveMQ、Spring以及Spring MVC是构建高效、可扩展的Web应用程序的常见实践。这个"activeMQ+spring+springmvc整合示例"旨在帮助开发者理解如何将这三者结合,以实现消息队列(Message Queue)的...

    39、ActiveMQ.pdf

    在本文中,我们将深入探讨ActiveMQ,这是一个广泛使用的开源消息中间件,属于Apache软件基金会的项目。ActiveMQ是基于Java的消息传递平台,它允许应用程序通过消息传递进行通信,从而实现解耦、流量控制和异步处理。...

    ActiveMQ+Camel+Spring+jms Demo(一)

    在实际的"ActiveMQ+Camel+Spring+jms Demo"项目中,开发者可能首先会在Spring配置中定义一个JMS模板,用于发送消息;然后,创建一个消息监听器,由Spring容器管理,用于接收和处理消息。Camel可以通过其强大的路由...

    springboot与activemq结合以及mq延迟demo

    本示例主要探讨如何将Spring Boot与ActiveMQ结合,实现MQ延迟功能,这对于一些需要定时触发的任务,如订单超时处理、定时发送邮件等场景非常有用。 首先,我们需要理解Spring Boot和ActiveMQ的基本概念。Spring ...

    springboot整合jms进行邮件的发送

    在本文中,我们将深入探讨如何使用Spring Boot与Java消息服务(JMS)来发送电子邮件,包括文本、HTML、图片和附件。Spring Boot以其强大的依赖管理和自动化配置能力,使得集成各种功能变得异常简单,包括集成JMS进行...

    Spring in Action(第二版 中文高清版).part2

    16.4.3 在JSF页面中使用Spring Bean 16.4.4 在JSF中暴露应用程序环境 16.5 Spring中带有DWR的支持Ajax的应用程序 16.5.1 直接Web远程控制 16.5.2 访问Spring管理的Bean DWR 16.6 小结 附录A 装配Spring A.1 ...

    spring整合其他框架

    Spring支持Ehcache作为二级缓存,通过声明式配置,可以将数据存储在内存中,减少数据库查询,提高响应速度。 5. Spring与Quartz整合:Quartz是用于任务调度的开源库。Spring与Quartz结合,可以方便地创建、管理和...

    0927分布式消息通信-ActiveMQ1

    9. **Spring整合**:Spring框架与ActiveMQ的集成使得在应用中使用消息传递变得更加方便。 10. **发送策略**:消息可以设置为持久化或非持久化,以平衡性能和可靠性。 11. **消费模式**:消费者既可以采用Pull模式...

    JAVA邮件发送系统项目

    在Java中,我们可以使用JavaMail API来处理邮件发送。JavaMail API是一个开源库,它提供了与多种邮件协议(如SMTP、POP3、IMAP)交互的接口。要使用这个API,你需要在项目中引入相关的jar包,例如`javax.mail`和`...

    Spring in Action(第二版 中文高清版).part1

    16.4.3 在JSF页面中使用Spring Bean 16.4.4 在JSF中暴露应用程序环境 16.5 Spring中带有DWR的支持Ajax的应用程序 16.5.1 直接Web远程控制 16.5.2 访问Spring管理的Bean DWR 16.6 小结 附录A 装配Spring A.1 ...

    为Spring mvc、Thymelaaf模板引擎、H2数据库、Lombok和消息传递Spring Boot应用程序

    最后,他们可能会实现一个简单的消息传递示例,展示如何在Spring Boot应用中发送和接收消息。 通过深入研究这个项目,你可以学习到如何有效地组合这些技术,构建出一个功能完备、高效且易于维护的Web应用。这将有助...

    Springmvc+JPA(Hibernate4)+redis+activemq

    4. **ActiveMQ** 用于消息队列,支持后台任务的异步处理,如批量数据处理、邮件发送等,避免阻塞主线程,提高系统响应速度。 整合这些技术时,还需要关注以下几点: - **全局异常拦截统一处理**:通过Spring MVC的...

    SpringBootWork-ActiveMQ-Ehcache-Mail-Mybatis-Redis-Schedule-Web.zip

    在Spring Boot中,使用`spring-boot-starter-cache`起步依赖,并配置Ehcache,可以实现本地缓存,降低数据库压力,提高响应速度。 4. **Mail服务**: Spring Boot提供了发送邮件的功能,通过`spring-boot-starter-...

    Spring in Action(第2版)中文版

    16.4.3在jsf页面中使用springbean 16.4.4在jsf中暴露应用程序环境 16.5spring中带有dwr的支持ajax的应用程序 16.5.1直接web远程控制 16.5.2访问spring管理的beandwr 16.6小结 附录a装配spring a.1下载spring ...

    spring boot 实践学习案例,与其它组件整合

    - Spring Boot 业务应用,包括 定时任务、上传文件、发送邮件、Doc文档操作 等。 - springboot-ajax - Spring Boot AJAX 跨域,包括 JSONP、Node.js与SpringBoot集成使用反向代理 等。 - springboot-...

Global site tag (gtag.js) - Google Analytics