部分博客中描述的使用拦截器怎么用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 {@AroundInvokepublic 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{//定义连接对象和sessionTopicConnection topicConnection=null;TopicSession topicSession = null;QueueConnection queueConnection=null;QueueSession queueSession = null;try {//创建contextProperties 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");//获取ConnectiontopicConnection=topicFactory.createTopicConnection();//获取SessiontopicSession=topicConnection.createTopicSession(false, TopicSession.AUTO_ACKNOWLEDGE);//获取destinationTopic 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");//获取ConnectionqueueConnection=queueFactory.createQueueConnection();//获取SessionqueueSession=queueConnection.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);//获取destinationQueue 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. 微服务中的异步消息通讯

    前言 在上一篇文章中,我们说到了异步消息通讯,下面这篇文章呢,大部分内容是翻译来自于这篇微软的文章,所以其内容还是具有一定的理论指导意义的. 当我们跨多个微服务进行内部通讯的时候,异步消息和事件驱动至 ...

  2. 仿牛客网项目第五,六章:异步消息系统和分布式搜索引擎(详细步骤和思路)

    目录 1. Kafka:构建TB级异步消息系统 1.0 同步/异步消息的区别 1.1 项目的目的 1. 2 阻塞队列实现异步消息系统 1.4 Kafka入门 1.5 Spring整合Kafka 1.6 ...

  3. Spring framework(10):集成 JMS 异步消息队列(ActiveMQ)

    JMS 和 Apache-ActiveMQ 简介 JMS(Java Message Service,Java 消息服务)是一个 Java 面向消息中间件(MOM)的 API,用于 Java 应用程序或 ...

  4. Flowmill :为分布式应用程序世界构建的网络可观察性解决方案

    https://docs.flowmill.com/ 目录 How Flowmill Works Flowmill 收集什么 检测网络可靠性和性能问题 管理网络传输成本 分析应用程序行为 Flowmi ...

  5. ZooKeeper程序员指南--使用ZooKeeper开发分布式应用程序

    ZooKeeper程序员指南 开发使用ZooKeeper的分布式应用程序 介绍 ZooKeeper数据模型 ZNodes 手表 数据访问 短暂的节点 序列节点 - 唯一命名 容器节点 TTL节点 在Z ...

  6. EJB与JAVA BEAN_J2EE的异步消息机制

    EJB与JAVA BEAN_J2EE的异步消息机制 EJB与JAVA BEAN的区别 Java Bean 是可复用的组件,对Java Bean并没有严格的规范,理论上讲,任何一个Java类都可以是一个 ...

  7. MassTransit - .NET Core 的分布式应用程序框架

    简介 MassTransit 是一个免费的.开源的.NET 分布式应用程序框架.MassTransit 使创建应用程序和服务变得容易,这些应用程序和服务利用基于消息的松散耦合异步通信来实现更高的可用性 ...

  8. .NET Core 3.0 的新改进:针对分布式应用程序的故障诊断和监控

    由于分布式应用是由多个组件组成的,且这些组件往往是由不同的团队拥有和操作,所以在与应用程序发生交互时,就会需要跨多个组件执行代码的分布式跟踪.如果用户遇到了问题,想要确定是哪个组件出现了差错,基本就是 ...

  9. spring boot注释_使用Spring Boot和注释支持配置Spring JMS应用程序

    spring boot注释 1.简介 在以前的文章中,我们学习了如何使用Spring JMS配置项目. 如果查看有关使用Spring JMS进行消息传递的文章介绍 ,您会注意到它是使用XML配置的. ...

最新文章

  1. python之进程和线程的对比
  2. ORM-Dapper:Dapper百科
  3. 【iOS】NSNumberFormatter
  4. SQL Server 批量插入数据的两种方法(转)
  5. 反爬虫机制和破解方法汇总
  6. 腾讯被深圳南山法院强制执行:执行标的25元;B站就招聘争议致歉;华为云回应是否将独立运作|极客头条...
  7. Aiseesoft iPhone Unlocker for Mac解锁密码?详细教程
  8. 单片机开发,stm32开发,串口下载软件,flymcu
  9. 【python】微信朋友圈数据分析及可视化(爬虫+数据挖掘)
  10. 安装装ankhsvn
  11. 主成分与因子分析异同_主成分分析和因子分析有什么区别?
  12. python如何调整图片大小_Python实现图片尺寸缩放脚本
  13. Android实验五-组件通信2
  14. 【企业】读纸牌屋,把握人性
  15. 你的代码暴漏了你的年龄(毕业设计)--技术文档+程序源代码
  16. 黑龙江农垦科技职业学院喜迎寒假多校联赛2(快乐ak场)
  17. 华为分析联运活动,助您提升游戏总体付费
  18. 程序员工资一般多少钱一个月?【推荐】
  19. max等聚合函数和group by搭配使用的注意事项
  20. alibaba-COLA框架module分析

热门文章

  1. 使用ionic cordova build android --release --prod命令打包报错解决方法
  2. 第三方账号登陆的过程及由此引发的血案
  3. 盘点2015年数据中心领域十大SDN市场领导者
  4. jQuery hash
  5. MonolithFirst:单体应用优先策略
  6. gridview、datalist、repeater、FormView、DetailsView的区别详解
  7. 20175330 数据结构-排序(选做)
  8. [SDOI2008]Sandy的卡片
  9. 后台返回的数据换行显示
  10. asp遍历前端的所有控件