部分博客中描述的使用拦截器怎么用EJB公布的WebService加入缓存,这样能够提高WebService的响应效率。但是即使是这样做,还是要经历网络的传输的。于是决定在调用WebService的程序本地也加入EJB方法缓存。假设WebService调用的结果已经存在于本地缓存中,就直接从内存中拿数据,不用再訪问WebService了。

架构图例如以下所看到的

可是还有一个问题又出现了,那就是WebService中的缓存和客户程序本地缓存的同步问题。这个问题能够详细描写叙述例如以下:

当提供WebService的程序的数据库中的数据发生改变后(程序运行了增删改方法后),就须要将WebService的缓存清空,由于那些是脏数据。但是调用WebService的客户程序本地的缓存却没有清空。

如何解决问题呢?如何才干清空WebService缓存的同一时候也清空调用client本地的缓存呢?利用JMS的消息机制就能够解决这一问题

详细思路

在WebService服务端创建一个JMS
Topic,起名CacheTopic

当服务端运行增删改方法后,向CacheTopic中发一条消息

客户程序在自己的server中部署Message Driven Bean,监听CacheTopic中的消息,收到消息后清空本地缓存

架构图例如以下所看到的

项目中使用的AS都是JBoss,在JBoss中加入JMS
Topic的方法是在deploy文件夹下部署一个Destination描写叙述文件,文件名称符合*-service.xml。

本项目中使用的CacheTopic的部署文件内容例如以下

<?xml version="1.0" encoding="UTF-8"?

>

<server>

   <!--使用jboss messaging定义topic-->
<mbean code="org.jboss.jms.server.destination.TopicService"
name="jboss.messaging.destination:service=Topic,name=CacheTopic"
xmbean-dd="xmdesc/Topic-xmbean.xml">
<depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>
<depends>jboss.messaging:service=PostOffice</depends>
<attribute name="JNDIName" >topic/CacheTopic</attribute>
</mbean> </server>

服务端程序在运行增删改方法后,不仅要清除WebService中的缓存。还要向CacheTopic中发送消息

上篇博客中的拦截器改动例如以下(主要是加入了发送消息的功能):

public class CacheClearSyncInterceptor {
@AroundInvoke
public Object clearCache(InvocationContext context) throws Exception{ //运行目标方法
Object returnObj =context.proceed(); /**************************清空本地缓存 begin**************************************/
System.out.println("清空前的缓存数:"+CacheHandler.getInstance().getCache().getSize());
//清空本地缓存
CacheHandler.getInstance().clearCache();
System.out.println("清空后的缓存数:"+CacheHandler.getInstance().getCache().getSize());
/**************************清空本地缓存 end**************************************/ //发送消息到CacheTopic,实现缓存同步
StringBuilder txtMsgBuilder = new StringBuilder();
txtMsgBuilder.append("【gxpt-jc】系统运行了【")
.append(context.getTarget().getClass().getName())
.append(".")
.append(context.getMethod().getName())
.append("】")
.append("方法,须要同步缓存");
MessageSender.send(txtMsgBuilder.toString(), DestinationType.TOPIC,"topic/CacheTopic","192.168.24.48:1199"); return returnObj;
} }

上面用到的消息发送者类MessageSender的代码例如以下

public class MessageSender {

	/**
* @MethodName : send
* @Description : 发送消息
* @param msg 消息
* @param type 目的地类型:TOPIC或QUEUE
* @param destinationJndi 目的地的jndi名称
* @param url 目的地url
*/
public static void send(String msg,DestinationType type,String destinationJndi,String url) throws Exception{ //定义连接对象和session
TopicConnection topicConnection=null;
TopicSession topicSession = null;
QueueConnection queueConnection=null;
QueueSession queueSession = null; try {
//创建context
Properties props = new Properties();
props.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
props.setProperty("java.naming.provider.url", url);
Context ctx = new InitialContext(props); /************************************发消息给TOPIC begin******************************************************/
if(type==DestinationType.TOPIC){
TopicConnectionFactory topicFactory=(TopicConnectionFactory)ctx.lookup("ConnectionFactory"); //获取Connection
topicConnection=topicFactory.createTopicConnection(); //获取Session
topicSession=topicConnection.createTopicSession(false, TopicSession.AUTO_ACKNOWLEDGE); //获取destination
Topic topic=(Topic)ctx.lookup(destinationJndi); //创建消息发送者
TopicPublisher publisher=topicSession.createPublisher(topic); //创建消息
TextMessage txtMsg = topicSession.createTextMessage(msg);
//发送消息
publisher.publish(txtMsg); }
/************************************发消息给TOPIC end******************************************************/ /************************************发消息给QUEUE begin******************************************************/
if(type==DestinationType.QUEUE){
QueueConnectionFactory queueFactory=(QueueConnectionFactory)ctx.lookup("ConnectionFactory"); //获取Connection
queueConnection=queueFactory.createQueueConnection(); //获取Session
queueSession=queueConnection.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE); //获取destination
Queue queue=(Queue)ctx.lookup(destinationJndi); //创建消息发送者
QueueSender sender=queueSession.createSender(queue); //创建消息
TextMessage txtMsg = queueSession.createTextMessage(msg);
//发送消息
sender.send(txtMsg);
}
/************************************发消息给QUEUE end******************************************************/ } finally{
//关闭对象
if(topicConnection!=null && topicSession!=null){
topicSession.close();
topicConnection.close();
} if(queueConnection!=null && queueSession!=null){
queueSession.close();
queueConnection.close();
}
} } }

client接收消息的MDB的代码例如以下

@MessageDriven(
activationConfig={
@ActivationConfigProperty(propertyName="destinationType",propertyValue="javax.jms.Topic"),
@ActivationConfigProperty(propertyName="destination",propertyValue="topic/CacheTopic"),
@ActivationConfigProperty(propertyName="providerAdapterJNDI", propertyValue="java:/RemoteJMSProvider")
}
)
public class KSCacheSyncMdb implements MessageListener{ public void onMessage(Message msg){
try {
//获取消息文本
TextMessage txtMsg = (TextMessage)msg;
//显示文本消息
System.out.println("因为"+txtMsg.getText()); /**************************清空本地缓存 begin**************************************/
System.out.println("清空前的缓存数:"+CacheHandler.getInstance().getCache().getSize());
//清空本地缓存
CacheHandler.getInstance().clearCache();
System.out.println("清空后的缓存数:"+CacheHandler.getInstance().getCache().getSize());
/**************************清空本地缓存 end**************************************/ } catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
} }

由于在JBoss5.1.0中部署的MDB默认仅仅能监听本地Destination中的消息。为了让MDB能够监听远程Destination中的消息。client仍需再部署一个RemoteJMSProvider描写叙述文件,文件名称相同需符合*-service.xml。文件内容例如以下

<?

xml version="1.0" encoding="UTF-8"?>
<server>
<mbean code="org.jboss.jms.jndi.JMSProviderLoader" name="jboss.messaging:service=JMSProviderLoader,name=RemoteJMSProvider">
<attribute name="ProviderName">RemoteJMSProvider</attribute>
<attribute name="ProviderAdapterClass">
org.jboss.jms.jndi.JNDIProviderAdapter
</attribute>
<!-- The combined connection factory -->
<attribute name="FactoryRef">XAConnectionFactory</attribute>
<!-- The queue connection factory -->
<attribute name="QueueFactoryRef">XAConnectionFactory</attribute>
<!-- The topic factory -->
<attribute name="TopicFactoryRef">XAConnectionFactory</attribute>
<!-- Uncomment to use HAJNDI to access JMS-->
<attribute name="Properties">
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=192.168.24.48:1199
</attribute>
</mbean> </server>

这样就实现了分布式应用程序缓存同步的

版权声明:本文博主原创文章,博客,未经同意不得转载。

JMS分布式应用程序异步消息解决方案EhCache 高速缓存同步问题的更多相关文章

  1. JMS异步消息机制

    企业消息系统 Java Message Service 是由 Sun Microsystems 开发的,它为 Java 程序提供一种访问 企业消息系统 的方法.在讨论 JMS 之前,我们分来析一下企业 ...

  2. 1.异步消息Jms及其JmsTemplate的源代码分析,消息代理ActiveMQ

    一. 介绍 借助Spring,有多种异步消息的可选方案,本章使用Jms.Jms的消息模型有两种,点对点消息模型(队列实现)和发布-订阅消息模型(主题). 图1.点对点消息模型(一对一) 图2.发布-订 ...

  3. (十七)SpringBoot之使用异步消息服务jms之ActiveMQ

    一.引入maven依赖 <dependencies> <dependency> <groupId>org.springframework.boot</grou ...

  4. 基于.NET平台的分布式应用程序的研究

    摘 要:.NET框架是Microsoft用于生成分布式Web应用程序和Web服务的下一代平台.概述了用于生成分布式应用程序的.NET框架的基本原理.重点讲述了.NET框架的基础:公共语言运行时(CLR ...

  5. Android应用程序线程消息循环模型分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6905587 我们知道,Android应用程序是 ...

  6. Android异步消息机制

    Android中的异步消息机制分为四个部分:Message.Handler.MessageQueue和Looper. 其中,Message是线程之间传递的消息,其what.arg1.arg2字段可以携 ...

  7. 使用Spring JMS轻松实现异步消息传递

    异步进程通信是面向服务架构(SOA)一个重要的组成部分,因为企业里很多系统通信,特别是与外部组织间的通信,实质上都是异步的.Java消息服务(JMS)是用于编写使用异步消息传递的JEE应用程序的API ...

  8. #研发中间件介绍#异步消息可靠推送Notify

    郑昀 基于朱传志的设计文档 最后更新于2014/11/11 关键词:异步消息.订阅者集群.可伸缩.Push模式.Pull模式 本文档适用人员:研发   电商系统为什么需要 NotifyServer? ...

  9. 三.RabbitMQ之异步消息队列(Work Queue)

    上一篇文章简要介绍了RabbitMQ的基本知识点,并且写了一个简单的发送和接收消息的demo.这一篇文章继续介绍关于Work Queue(工作队列)方面的知识点,用于实现多个工作进程的分发式任务. 一 ...

随机推荐

  1. C#的百度地图开发(三)依据坐标获取位置、商圈及周边信息

    原文:C#的百度地图开发(三)依据坐标获取位置.商圈及周边信息 我们得到了百度坐标,现在依据这一坐标来获取相应的信息.下面是相应的代码 public class BaiduMap { /// < ...

  2. Android Studio使用心得 - 简单介绍与环境配置

    FBI Warning:欢迎转载,但请标明出处:http://blog.csdn.net/codezjx/article/details/38544823,未经本人允许请勿用于商业用途.感谢支持! 关 ...

  3. Failed to load libGL.so问题解决

    Ubuntu 14.04下启动模拟设备Android 4.2.2的时候报错: failed to load libgl.so 先用locate 命令定位libGL库, 然后加入�一个链接就可以: de ...

  4. 微端 代码project as air 分享

    分享 ^_^ 1. 使用 air , as . 2. 微端下载和更新技术 成功上线棋牌游戏.它可用于传统的游戏开发. 地址: http://download.csdn.net/detail/stone ...

  5. 【Android】-- adb shell 命令探索

    ADB是什么,做android开发的没有不知道的. window下执行cmd,输入adb help就会打印adb都可以做的事情,包含 adb push ..adb pull .. adb device ...

  6. 用友CDM系统期初导入商品资料经验

    1.       倒入商品资料,是导入表spkfk(商品档案表).spkfjc(商品总结存表),主要是将spkfk全部编码导入. 2.       导入客商资料,是导入表mchk(业务单位登记表).m ...

  7. TCP header

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3Vzc2VyNDM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA ...

  8. C++ 复制功能

    C++ 复制功能 说C++复制功能,它可能不是很熟悉.类中的拷贝构造函数和赋值操作符.可是其实或许我们一不小心就会忽略编译器所做的一些默认操作.引起晦涩的错误.以下分析几种场景: 一.场景一:所有默认 ...

  9. uIP中国的协议文件:Ch01

    uIP0.9 参考 by Doxygen 1.3.3 Tue Oct 7 15:51:00 2003 译: fishOnFly(鱼在飞) uIP-refman中文pdf下载 第1章  uIP TCP/ ...

  10. Java的Log系统介绍和切换(转)

    Java的log系统比较繁杂.在这里梳理一下.本文只涉及log系统介绍和处理log系统之间的切换.不涉及如何配置和使用. 具体的log系统 Log4j:准确的说是log4j 1.x版.是之前使用最广泛 ...