关于ActiveMQ接收消息,以及事务,hibernat事务的处理方法

最新项目上应用到ActiveMQ开源框架,其中也发现了一些问题,总结了一些浅薄的经验,本着开源,其他程序员少走一些弯路的宗旨,特与人分享,有好的方法,好的经验可以互相分享。

上正文(因为项目使用grails框架groovy语言,但是其他语言大致想通):

class ChargeRespReceiverService {

 // ConnectionFactory :连接工厂,JMS 用它创建连接
    private static ConnectionFactory connectionFactory;
    // Connection
    private static Connection topicConn;
    // Session: 一个响应发送或接收消息的线程
    private static Session topicSession;
    // Topic: 响应消息的目的地;消息发送给谁.
    private static Topic topicPay = null;
    // MessageConsumer:响应消息接收者
    private static MessageConsumer topicConsumer;
    //使用静态块初始化JMS连接
    static {
        initJms();
    }
    
    /**
     * 初始化
     */
    static void initJms() {
        // 构造ConnectionFactory实例对象,此处采用ActiveMq的实现 Constants.JMS_URL--JMS链接 Constants.PAY_TOPIC--TOPIC名称 "myChargeClient" 为注册到MQ的客户端ID,取唯一值
        try {
            connectionFactory = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER, ActiveMQConnection.DEFAULT_PASSWORD, Constants.JMS_URL);
            topicConn = connectionFactory.createConnection();
            topicConn.setClientID("myChargeClient");
            //true为开启事务模式,onMessage方法完全执行成功之后签名,过程中如果出现异常自动回滚,消息还在,false为接收之后自动签名,没有回滚
            //还有一点要注意,Session.AUTO_ACKNOWLEDGE为MQ自动签名机制,但是如果MQ中如果有之前已经序列化的内容,经测试MQ不会自动去签名,此时需要调用topicSession.commit()方法进行手动签名
            topicSession = topicConn.createSession(true, Session.AUTO_ACKNOWLEDGE);
            topicPay = topicSession.createTopic(Constants.PAY_TOPIC);
            topicConn.start();
        } catch (JMSException e) {
            e.printStackTrace();
            if (topicConn != null) {
                try {
                    topicConn.close();
                    topicConn = null;
                } catch (JMSException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }
    
    /**
     * 接收消息
     * @param selector
     * @return
     * @throws Exception
     */
    static synchronized MessageConsumer receiveResp(String selector) throws Exception {
    		//"chargeClient"为注册到MQ中的用户名,这个建议不要重复,方便在管理后台查看消息数量
        topicConsumer = topicSession.createDurableSubscriber(topicPay, "chargeClient", selector, Boolean.FALSE);
        return topicConsumer;
    }
    
    /**
     * 监听MQ的消息
     */
    public void chargeRespReceive() {

        println "充值服务监听启动...........";


        try {
        		//此处进行选择,过滤掉不需要的消息、这个机制非常好
            String selector = "receiver = 'charge'";
            MessageConsumer consumer = receiveResp(selector);
            String s = consumer.getMessageSelector();
            consumer.setMessageListener(new MessageListener() {
                public void onMessage(Message arg0) {
                    MapMessage msg = (MapMessage) arg0;
                    try {
                        String srvCode = msg.getString("srvCode");
                        String outOrder = msg.getString("outOrder");
                        String feedback = msg.getString("feedback");
                        String reason = msg.getString("reason");
                        String chanelId = msg.getString("chanelId");
                        Charge charge = Charge.get(outOrder as long);
                        if (null != charge) {
                            charge.tradeFeedback = feedback;
                            charge.setTradeReason(reason==null?"":reason); //reason;
                            charge.setTradeStatus("2");//处理完毕
                            //充值已经操作成功
                            if ("succ".equals(charge.tradeFeedback)) {
                                charge.tradeFeedback = chargeService.chargeCustomerInfo(charge, chanelId) ? "succ" : "fail";//成功之后需要处理账务
                            } else if ("fail".equals(charge.tradeFeedback)) { //打款平台处理失败
                                charge.tradeFeedback = "fail";
                                sendChargeFeedBackEmail(charge);//失败发送Email

                            }
                            //此处要注意,在onMessage这个内部类的方法内,或者线程内使用Hibernate方式会出现事务问题,这个要加上相应的事务
                            //在grails中Domain的事务方式比较方便例如:Charge.withTransaction {status -> //开启事务}
                            //Charge.update(charge);
                            Charge.executeUpdate("update Charge set tradeFeedback = '"+charge.tradeFeedback+"', tradeReason = '"+charge.tradeReason+"', tradeStatus = "+charge.tradeStatus+", tradeDonedate = sysdate where id = "+charge.id as String);


                        }
                        //这个就是提到的,如果接收已经序列化到MQ服务器本地文件,或者数据库中的消息时会发现消息取出之后并没有减少的问题,
                        //手动提交之后解决该问题(相关序列化的文章,在网上有很多)
                        topicSession.commit();
                        
                    } catch (Exception e) {
                        
                        e.printStackTrace();
                    }

                }
            });
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

最后的最后,别忘了,启动这个监听

在BootStrap.groovy中加入启动

//启动充值反馈监听
chargeRespReceiverService.chargeRespReceive();

你可能感兴趣的:(activemq)