JMS分布式应用程序异步消息解决方案EhCache高速缓存同步问题
部分博客中描述的使用攔截器怎么用EJB公布的WebService加入緩存,這樣能夠提高WebService的響應(yīng)效率。但是即使是這樣做,還是要經(jīng)歷網(wǎng)絡(luò)的傳輸?shù)摹S谑菦Q定在調(diào)用WebService的程序本地也加入EJB方法緩存。假設(shè)WebService調(diào)用的結(jié)果已經(jīng)存在于本地緩存中,就直接從內(nèi)存中拿數(shù)據(jù),不用再訪問WebService了。
?
架構(gòu)圖例如以下所看到的
可是還有一個(gè)問題又出現(xiàn)了,那就是WebService中的緩存和客戶程序本地緩存的同步問題。這個(gè)問題能夠詳細(xì)描寫敘述例如以下:
當(dāng)提供WebService的程序的數(shù)據(jù)庫中的數(shù)據(jù)發(fā)生改變后(程序運(yùn)行了增刪改方法后),就須要將WebService的緩存清空,由于那些是臟數(shù)據(jù)。但是調(diào)用WebService的客戶程序本地的緩存卻沒有清空。
?
如何解決問題呢?如何才干清空WebService緩存的同一時(shí)候也清空調(diào)用client本地的緩存呢?利用JMS的消息機(jī)制就能夠解決這一問題
?
詳細(xì)思路
在WebService服務(wù)端創(chuàng)建一個(gè)JMS Topic,起名CacheTopic
當(dāng)服務(wù)端運(yùn)行增刪改方法后,向CacheTopic中發(fā)一條消息
客戶程序在自己的server中部署Message Driven Bean,監(jiān)聽CacheTopic中的消息,收到消息后清空本地緩存
?
?
架構(gòu)圖例如以下所看到的
項(xiàng)目中使用的AS都是JBoss,在JBoss中加入JMS Topic的方法是在deploy文件夾下部署一個(gè)Destination描寫敘述文件,文件名稱符合*-service.xml。
?
本項(xiàng)目中使用的CacheTopic的部署文件內(nèi)容例如以下
<?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>
服務(wù)端程序在運(yùn)行增刪改方法后,不僅要清除WebService中的緩存。還要向CacheTopic中發(fā)送消息
上篇博客中的攔截器改動(dòng)例如以下(主要是加入了發(fā)送消息的功能):
public class CacheClearSyncInterceptor {@AroundInvokepublic Object clearCache(InvocationContext context) throws Exception{//運(yùn)行目標(biāo)方法Object returnObj =context.proceed();/**************************清空本地緩存 begin**************************************/System.out.println("清空前的緩存數(shù):"+CacheHandler.getInstance().getCache().getSize());//清空本地緩存CacheHandler.getInstance().clearCache();System.out.println("清空后的緩存數(shù):"+CacheHandler.getInstance().getCache().getSize());/**************************清空本地緩存 end**************************************///發(fā)送消息到CacheTopic,實(shí)現(xiàn)緩存同步StringBuilder txtMsgBuilder = new StringBuilder();txtMsgBuilder.append("【gxpt-jc】系統(tǒng)運(yùn)行了【").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;}}
上面用到的消息發(fā)送者類MessageSender的代碼例如以下
public class MessageSender {/*** @MethodName : send* @Description : 發(fā)送消息* @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 {//創(chuàng)建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);/************************************發(fā)消息給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);//創(chuàng)建消息發(fā)送者TopicPublisher publisher=topicSession.createPublisher(topic);//創(chuàng)建消息TextMessage txtMsg = topicSession.createTextMessage(msg);//發(fā)送消息publisher.publish(txtMsg);}/************************************發(fā)消息給TOPIC end******************************************************//************************************發(fā)消息給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);//創(chuàng)建消息發(fā)送者QueueSender sender=queueSession.createSender(queue);//創(chuàng)建消息TextMessage txtMsg = queueSession.createTextMessage(msg);//發(fā)送消息sender.send(txtMsg);}/************************************發(fā)消息給QUEUE end******************************************************/} finally{//關(guān)閉對象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("因?yàn)?#34;+txtMsg.getText());/**************************清空本地緩存 begin**************************************/System.out.println("清空前的緩存數(shù):"+CacheHandler.getInstance().getCache().getSize());//清空本地緩存CacheHandler.getInstance().clearCache();System.out.println("清空后的緩存數(shù):"+CacheHandler.getInstance().getCache().getSize());/**************************清空本地緩存 end**************************************/} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e.getMessage());}}}由于在JBoss5.1.0中部署的MDB默認(rèn)僅僅能監(jiān)聽本地Destination中的消息。為了讓MDB能夠監(jiān)聽遠(yuǎn)程Destination中的消息。client仍需再部署一個(gè)RemoteJMSProvider描寫敘述文件,文件名稱相同需符合*-service.xml。文件內(nèi)容例如以下
<?
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>
這樣就實(shí)現(xiàn)了分布式應(yīng)用程序緩存同步的
版權(quán)聲明:本文博主原創(chuàng)文章,博客,未經(jīng)同意不得轉(zhuǎn)載。
總結(jié)
以上是生活随笔為你收集整理的JMS分布式应用程序异步消息解决方案EhCache高速缓存同步问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: git学习——Git 基础要点【转】
- 下一篇: Rust的随机数