<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"> <!-- 加载DataChange的环境变量 --> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="file:${appHome}/datachange.properties" /><!-- webserver环境和线上环境一定要设appHome,单元测试环境下appHome为null --> <property name="ignoreResourceNotFound" value="true" /> <property name="ignoreUnresolvablePlaceholders" value="true" /> <property name="properties" ref="localDataChangeProperties" /><!-- 本地环境下使用此值 --> </bean> <bean name="localDataChangeProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="location" value="classpath:configDefault/datachange.properties" /> </bean> <!-- 导入默认的DataChange的发送者的配置 --> <import resource="classpath:dataChangeConfigDefault/spring-dataChange-sender.xml" /> <context:component-scan base-package="com.xxxpiao.datachange" /> </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- 加载DataChange的环境变量 --> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="file:${appHome}/dataChange-receiver.properties" /><!-- webserver环境和线上环境一定要设appHome,单元测试环境下appHome为null --> <property name="ignoreResourceNotFound" value="true" /> <property name="ignoreUnresolvablePlaceholders" value="true" /> <property name="properties" ref="localDataChangeProperties" /><!-- 本地环境下使用此值 --> </bean> <bean name="localDataChangeProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="location" value="classpath:/configDefault/dataChange-receiver.properties" /> </bean> <bean name="betGameIssueOpenAwardFilter" class="com.xxx.datachange.common.domain.FilterConfig"> <property name="dataType" value="bet_game_issue"></property> </bean> <bean name="betIssueDataChangeListener" class="com.xxx.betcart.server.datachange.BetIssueDataChangeListener" /> <bean name="changeHandleMapping" class="com.xxx.datachange.client.domain.ChangeHandleMapping"> <property name="sender" value="coreservice"></property> <property name="receiver" value="group-betcart"></property> <property name="dataChangeListener" ref="betIssueDataChangeListener" /> <property name="filterConfigList"> <list> <ref bean="betGameIssueOpenAwardFilter"></ref> </list> </property> </bean> <bean name="betPlanPackageFilter" class="com.xxx.datachange.common.domain.FilterConfig"> <property name="dataType" value="order"></property> </bean> <bean name="betPlanPackageDataChangeListener" class="com.xxx.betcart.server.datachange.BetPlanPackageDataChangeListener" > <property name="expertAccount" value="${dataChange.expertAccount}"/> </bean> <bean name="betPlanPackageChangeHandleMapping" class="com.xxx.datachange.client.domain.ChangeHandleMapping"> <property name="sender" value="coreservice"></property> <property name="receiver" value="group-betcart-planpackage"></property> <property name="dataChangeListener" ref="betPlanPackageDataChangeListener" /> <property name="filterConfigList"> <list> <ref bean="betPlanPackageFilter"></ref> </list> </property> </bean> <bean name="receiveManager" class="com.xxx.datachange.client.receive.ReceiveManager"> <property name="zkDataChangeRoot" value="/datachange/metaq" /> <property name="zkConnect" value="${dataChange.zkConnect}" /> <property name="changeHandleMappingList"> <list> <ref bean="changeHandleMapping"/> <ref bean="betPlanPackageChangeHandleMapping"/> </list> </property> <!-- 只处理发送时间在这个日期之后的消息,这样可以防止新应用接收到很久以前的消息 --> <property name="acceptMsgUpdateTimeAfterThis"> <bean factory-bean="dataChangeDateFormat" factory-method="parse"> <constructor-arg value="2014-05-06" /> </bean> </property> </bean> <bean id="dataChangeDateFormat" class="java.text.SimpleDateFormat"> <constructor-arg value="yyyy-MM-dd" /> </bean> </beans>
package com.xxxpiao.core.jms; import java.io.Serializable; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.ObjectMessage; import javax.jms.Session; import javax.jms.TextMessage; import org.springframework.jms.core.JmsTemplate; import org.springframework.jms.core.MessageCreator; import com.alibaba.fastjson.JSON; /** * 通用的消息发送类 * @project coreService * @author wellpha.wu * @date 2011-02-12 * Copyright (C) 2010-2012 www.2caipiao.com Inc. All rights reserved. */ public class MessageProducer { protected JmsTemplate jmsTemplate; /** * 使用jmsTemplate的send/MessageCreator()发送ObjectMessage类型的消息 */ public void sendMessage(final Serializable obj, Destination destination) { jmsTemplate.send(destination, new MessageCreator() { public Message createMessage(Session session) throws JMSException { ObjectMessage message = session.createObjectMessage(); message.setObject(obj); return message; } }); } public void sendTxtJSONMessage(final Serializable obj, Destination destination) { jmsTemplate.send(destination, new MessageCreator() { public Message createMessage(Session session) throws JMSException { TextMessage message = session.createTextMessage(); message.setText(JSON.toJSONString(obj)); return message; } }); } public void sendTxtMessage(final String text, Destination destination) { jmsTemplate.send(destination, new MessageCreator() { public Message createMessage(Session session) throws JMSException { TextMessage message = session.createTextMessage(); message.setText(text); return message; } }); } public void setJmsTemplate(JmsTemplate jmsTemplate) { this.jmsTemplate = jmsTemplate; } }
package com.xxxpiao.core.jms; import javax.jms.Destination; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.xxx.datachange.domain.DataChangeDO; public class DataChangePublisher extends MessageProducer { protected static final Logger logger = LoggerFactory.getLogger("data_change_log"); /** 消息队列 */ private Destination datachangeTopic; public void setDatachangeTopic(Destination datachangeTopic) { this.datachangeTopic = datachangeTopic; } public void senDataChangeMessage(final DataChangeDO dataChangeDO) { logger.info("datatypemessage--DataId:{},DataType:{},ChangeType:{}.", new Object[]{dataChangeDO.getDataId(),dataChangeDO.getDataType(),dataChangeDO.getChangeType()}); super.sendTxtJSONMessage(dataChangeDO, datachangeTopic); } }
package com.xxxpiao.datachange.manager; import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.annotation.PreDestroy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import com.xxx.datachange.constant.ChagneTypeConstant; import com.xxx.datachange.constant.ChangeFieldBitConstant; import com.xxx.datachange.constant.DataType; import com.xxx.datachange.domain.DataChangeDO; import com.xxxpiao.common.entity.member.Member; import com.xxxpiao.common.entity.member.MemberChargeLog; import com.xxxpiao.core.jms.DataChangePublisher; /** * 专门用于发送JMS消息 * */ @Service public class DataChangeManagerImpl { protected static transient final Logger logger = LoggerFactory.getLogger("data_change_log"); @Autowired @Qualifier("dataChangePublisher") private DataChangePublisher dataChangePublisher; private final ExecutorService threadPool = Executors.newFixedThreadPool(10); /** * 生成可靠的UUID,从DataChange1.0 升级到2.0,需要为每个消息设置一个UUID来去重。 * 以后会删除,其它程序不能使用这个函数 * @author zhixuan.chen * @date 2014年3月19日 * @return */ public static String generateUUID() { return UUID.randomUUID().toString(); } /** * 产生投注消息,包括合买,追号等投注消息 * @param orderID * @param planID */ public void createOrderPlanMessage(String uuid, long orderID,long planID,int orderType) { threadPool.execute(new CreateOrderTask(uuid, dataChangePublisher,orderID,planID,orderType)); } /** * 注册消息 * @param member */ public void createRegisterMessage(String uuid, Member member) { threadPool.execute(new CreateMemberTask(uuid, member,dataChangePublisher,ChagneTypeConstant.DATA_INSERT)); } /** * 注册消息 * @param member */ public void createRegisterMessage(String uuid, Member member,long type) { threadPool.execute(new CreateMemberTask(uuid, member,dataChangePublisher,ChagneTypeConstant.DATA_INSERT,type)); } /** * 实名认证消息 * @param member */ public void createRealNameMessage(String uuid, Member member) { threadPool.execute(new CreateMemberTask(uuid, member,dataChangePublisher,ChagneTypeConstant.DATA_MODIFY,ChangeFieldBitConstant.member_certNo)); } /** * 充值消息 * @param returnLog */ public void createChargeMessage(String uuid, MemberChargeLog returnLog) { threadPool.execute(new CreateChargeTask(uuid, returnLog,dataChangePublisher)); } /** * 设置大奖号码消息 * @param member */ public void createGetMoneyWayMessge(String uuid, Member member) { threadPool.execute(new CreateMemberTask(uuid, member,dataChangePublisher,ChagneTypeConstant.DATA_MODIFY,ChangeFieldBitConstant.member_get_money_phone)); } /** * 发送中奖消息 * @param planId * @param memberId */ public void createDrawMessage(String uuid, long planId,long memberId) { threadPool.execute(new CreateDrawTask(uuid, planId,memberId,dataChangePublisher)); } private static final class CreateChargeTask implements Runnable { private String uuid; private MemberChargeLog returnLog = null; private DataChangePublisher dataChangePublisher; public CreateChargeTask(String uuid, MemberChargeLog returnLog,DataChangePublisher dataChangePublisher) { this.uuid = uuid; this.returnLog = returnLog; this.dataChangePublisher = dataChangePublisher; } @Override public void run() { try { if(returnLog!=null) { logger.info("CreateChargeTask chargeid is {}",new Object[]{returnLog.getId()}); } DataChangeDO dataChangeDO = new DataChangeDO(); dataChangeDO.setUuid(uuid); dataChangeDO.setDataId(returnLog.getId()); dataChangeDO.setDataType(DataType.chargeLog); dataChangeDO.setChangeType(ChagneTypeConstant.DATA_INSERT); dataChangePublisher.senDataChangeMessage(dataChangeDO); } catch(Throwable e) { if(returnLog!=null) { logger.error("Run createChargeTas failed "+returnLog.getId(),e); }else { logger.error("Run createChargeTas failed",e); } } finally { this.returnLog = null; this.dataChangePublisher = null; } } } private static final class CreateMemberTask implements Runnable { private String uuid; private Member member = null; private DataChangePublisher dataChangePublisher; private byte optype; private long type = -1; public CreateMemberTask(String uuid, Member member,DataChangePublisher dataChangePublisher,byte optype) { this.uuid = uuid; this.member = member; this.optype = optype; this.dataChangePublisher = dataChangePublisher; } public CreateMemberTask(String uuid, Member member,DataChangePublisher dataChangePublisher,byte optype,long type) { this.uuid = uuid; this.member = member; this.optype = optype; this.type = type; this.dataChangePublisher = dataChangePublisher; } @Override public void run() { try { if(member!=null) { logger.info("CreateMemberTask memberid is {},optype is {},type {}",new Object[]{member.getId(),optype,type}); } DataChangeDO dataChangeDO = new DataChangeDO(); dataChangeDO.setUuid(uuid); dataChangeDO.setDataId(member.getId()); dataChangeDO.setDataType(DataType.member); dataChangeDO.setChangeType(optype); if(type!=-1) { dataChangeDO.setChangeFieldBit(type); } dataChangePublisher.senDataChangeMessage(dataChangeDO); } catch(Throwable e) { if(member!=null) { logger.error("Run CreateMemberTask failed "+member.getId(),e); }else { logger.error("Run CreateMemberTask failed",e); } } finally { this.member = null; this.dataChangePublisher = null; } } } private static final class CreateOrderTask implements Runnable { private long orderID ; private long planID ; private int orderType = -1; private long presentType = -1; private DataChangePublisher dataChangePublisher; /** * 唯一的消息ID,目前是UUID,用于dataChange1.0升级2.0的改造。 * 其它程序不可乱用,以后会删掉! * @author zhixuan.chen * @date 2014-03-19 */ private String uuid; public CreateOrderTask(String uuid, DataChangePublisher dataChangePublisher,long orderID,long planID,int orderType) { this.uuid = uuid; this.dataChangePublisher = dataChangePublisher; this.orderID = orderID; this.planID = planID; this.orderType = orderType; } public CreateOrderTask(String uuid, DataChangePublisher dataChangePublisher, long orderID, long planID, int orderType, int presentType) { this.uuid = uuid; this.dataChangePublisher = dataChangePublisher; this.orderID = orderID; this.planID = planID; this.orderType = orderType; this.presentType=presentType; } @Override public void run() { try { logger.info("CreateOrderTask orderID is {},planID is {},ordertype {},presentType {}",new Object[]{orderID,planID,orderType,presentType}); DataChangeDO dataChangeDO = new DataChangeDO(); dataChangeDO.setUuid(uuid); dataChangeDO.setDataId(orderID); dataChangeDO.setRelateId(planID); dataChangeDO.setChangeFieldBit(orderType); //这个地方吧放在oldStatus1 dataChangeDO.setOldStatus1((int)presentType); dataChangeDO.setDataType(DataType.order); dataChangeDO.setChangeType(ChagneTypeConstant.DATA_INSERT); dataChangePublisher.senDataChangeMessage(dataChangeDO); } catch(Throwable e) { logger.error("Run CreateOrderTask failed "+orderID,e); } finally { this.dataChangePublisher = null; } } } private static final class CreateDrawTask implements Runnable { private String uuid; private long planId; private long memberId; private DataChangePublisher dataChangePublisher; public CreateDrawTask(String uuid, long planId,long memberId,DataChangePublisher dataChangePublisher) { this.uuid = uuid; this.planId=planId; this.memberId=memberId; this.dataChangePublisher = dataChangePublisher; } @Override public void run() { try { logger.info("CreateDrawTask dataid is {},relateid is {}",new Object[]{planId,memberId}); DataChangeDO dataChangeDO = new DataChangeDO(); dataChangeDO.setUuid(uuid); dataChangeDO.setDataId(planId); dataChangeDO.setDataType(DataType.betPlan); dataChangeDO.setChangeType(ChagneTypeConstant.DATA_MODIFY); dataChangeDO.setRelateId(memberId); dataChangePublisher.senDataChangeMessage(dataChangeDO); } catch(Throwable e) { logger.error("Run CreateDrawTask failed ,{},{}",new Object[]{planId,memberId}); } finally { this.dataChangePublisher = null; } } } /** * 产生登陆信息 * @param memberId */ public void createClientLoginMessage(String uuid, long memberId) { threadPool.execute(new CreateClientLoginTask(uuid, dataChangePublisher,memberId)); } private static final class CreateClientLoginTask implements Runnable { private String uuid; private long memberId; private DataChangePublisher dataChangePublisher; public CreateClientLoginTask(String uuid, DataChangePublisher dataChangePublisher,long memberId) { this.uuid = uuid; this.memberId=memberId; this.dataChangePublisher = dataChangePublisher; } @Override public void run() { try { logger.info("CreateClientLoginTask dataid is {}",memberId); DataChangeDO dataChangeDO = new DataChangeDO(); dataChangeDO.setUuid(uuid); dataChangeDO.setDataId(memberId); dataChangeDO.setDataType(DataType.member); dataChangeDO.setChangeType(ChagneTypeConstant.DATA_MODIFY); dataChangeDO.setChangeFieldBit(ChangeFieldBitConstant.member_last_login_time); dataChangePublisher.senDataChangeMessage(dataChangeDO); } catch(Throwable e) { logger.error("Run CreateClientLoginTask failed ,{}",memberId); } finally { this.dataChangePublisher = null; } } } /** * 当spring容器停止的时候销毁资源 */ @PreDestroy public void destroy() { threadPool.shutdownNow(); logger.debug("发消息服务线程池关闭"); } // 增加代购消息发送给VIP系统添加财富值使用 public void createOrderPlanMessage(String uuid, long orderID,long planID,int orderType,int presentType) { threadPool.execute(new CreateOrderTask(uuid, dataChangePublisher,orderID,planID,orderType,presentType)); } }
package com.xxx.datachange.domain; public class DataChangeDO implements java.io.Serializable { private static final long serialVersionUID = 608049506513890581L; /** * 唯一的消息ID,目前是UUID,用于dataChange1.0升级2.0的改造。 * 其它程序不可乱用,以后会删掉! * @author zhixuan.chen * @date 2014-03-19 */ private String uuid; /** * 唯一的消息ID,目前是UUID,用于dataChange1.0升级2.0的改造。 * 其它程序不可乱用,以后会删掉! * @author zhixuan.chen * @date 2014年3月19日 * @return */ public String getUuid() { return uuid; } /** * 唯一的消息ID,目前是UUID,用于dataChange1.0升级2.0的改造。 * 其它程序不可乱用,以后会删掉! * @author zhixuan.chen * @date 2014年3月19日 * @param uuid */ public void setUuid(String uuid) { this.uuid = uuid; } /** * 数据记录ID,根据后面DATATYPE来判断,当 */ private long dataId; /** * 数据变化类型, 1表示消息类型对应表示member,2表示消息类型对应表示bet_order表,3表示消息类型对应表示member_charge_log表 */ private int dataType; /** * 1消息操作类型为插入,2消息操作类型为修改,3消息操作类型为设置提款号码 */ private byte changeType; /** * 原始状态1,跟具体业务部门协商,暂时没有使用 */ private int oldStatus1; /** * 原始状态2,跟具体业务部门协商,暂时没有使用 */ private int oldStatus2; /** * 变化字段索引,跟具体业务部门协商,暂时没有使用 */ private long changeFieldBit; /** * 与当前变化,关联ID。目前在投注消息中,DATAID是ORDERID,但是业务数据通过方案来查可能更快一下。给出了关联的方案主键为方案ID */ private long relateId; public long getDataId() { return dataId; } public void setDataId(long dataId) { this.dataId = dataId; } public int getDataType() { return dataType; } public void setDataType(int dataType) { this.dataType = dataType; } public byte getChangeType() { return changeType; } public void setChangeType(byte changeType) { this.changeType = changeType; } public int getOldStatus1() { return oldStatus1; } public void setOldStatus1(int oldStatus1) { this.oldStatus1 = oldStatus1; } public int getOldStatus2() { return oldStatus2; } public void setOldStatus2(int oldStatus2) { this.oldStatus2 = oldStatus2; } public long getChangeFieldBit() { return changeFieldBit; } public void setChangeFieldBit(long changeFieldBit) { this.changeFieldBit = changeFieldBit; } public void addChangeFieldBit(long bit){ this.changeFieldBit |= bit; } public long getRelateId() { return relateId; } public void setRelateId(long relateId) { this.relateId = relateId; } }