需求開發完成提測,測驗時發現activemq的listener在消費佇列訊息時,程式捕獲到例外,見下面log,
例外資訊很明顯,com.cn.yft.ora.entity.TAccReviewRecord這個class不存在,一看這個ClassNotFoundException例外,我聯想到以前用redis存盤熱資料的時候也出現過,
2021-01-12 20:14:14,734 [ERROR] [ListenCommonSyncMQService-1] [com.yft.busi.mq.CommonSyncMQService:40] [佇列發送]同步落地服務公司充值資訊發送失敗 javax.jms.JMSException: Failed to build body from content. Serializable class not available to broker. Reason: java.lang.ClassNotFoundException: com.cn.yft.ora.entity.TAccReviewRecord at org.apache.activemq.util.JMSExceptionSupport.create(JMSExceptionSupport.java:36) at org.apache.activemq.command.ActiveMQObjectMessage.getObject(ActiveMQObjectMessage.java:193) at com.yft.busi.mq.CommonSyncMQService.onMessage(CommonSyncMQService.java:31) at org.springframework.jms.listener.adapter.MessageListenerAdapter.onMessage(MessageListenerAdapter.java:341) at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:537) at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:497) at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:468) at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:325) at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:263) at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1102) at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1094) at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:991) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.ClassNotFoundException: com.cn.yft.ora.entity.TAccReviewRecord at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1928) at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1771) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:348) at org.apache.activemq.util.ClassLoadingAwareObjectInputStream.load(ClassLoadingAwareObjectInputStream.java:95) at org.apache.activemq.util.ClassLoadingAwareObjectInputStream.resolveClass(ClassLoadingAwareObjectInputStream.java:43) at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1868) at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1751) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2042) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1573) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431) at org.apache.activemq.command.ActiveMQObjectMessage.getObject(ActiveMQObjectMessage.java:191) ... 11 more
為什么會出現這樣的例外呢?
通常發生在系統物體類調整的時候,或,系統程式結構發生變化的時候,
先說本案,原因正是后者,原先是在同一個應用服務里使用了ActiveMQ,就是說同一個應用既是訊息生產者又是訊息消費者,生產者放入佇列的訊息TAccReviewRecord物件,那么,顯然,當同應用里的消費者MessageListener監聽到訊息后,獲取message攜帶的資料依然是程式里的TAccReviewRecord物件,
之所以出現了這個例外,是因為在開發新需求時,訊息生產者是在另一個服務,另一個服務的TAccReviewRecord的package與原先服務里TAccReviewRecord的package不同,從而導致了上文的ClassNotFoundException例外,
再說說之前redis存取熱資料遇到的這個例外,其原因是前者, 情況是設定快取呼叫了redis.set(String key, Object value)方法,即value直接指定的VO物件,后來,程式調整了VO的目錄結構,那么,重新發布到服務器上,再讀取指定key的值時,就出現了這個ClassNotFoundException,
【解決辦法】
為了規避類似問題,經過評估,采用了犧牲性能保證可用的策略,即,不再直接存放資料物件,而是將資料物件序列化為json串,讀取的時候同樣也做反序列化,
【附】
activemq producer代碼(服務A)
public int sendToQueue(String conFactory,String userName, String pwd, String tCPUrl, final Object message, String qMName) { ,,, Message testmessage = session.createObjectMessage((Serializable) message); // 發送訊息到目的地方 producer.send(testmessage); session.commit(); ,,, }
activemq consumer代碼(服務B) ----例外就是在第10行objectMessage.getObject()拋出來的
1 @Component("commonSyncMQService") 2 public class CommonSyncMQService implements MessageListener { 3 private final static Logger logger = LoggerFactory.getLogger(CommonSyncMQService.class); 4 5 @Override 6 public void onMessage(Message message) { 7 if (message instanceof ObjectMessage) { 8 final ObjectMessage objectMessage = (ObjectMessage) message; 9 try { 10 logger.info("同步落地服務公司充值資訊介面訊息佇列接收引數[{}]",objectMessage.getObject()); 11 TAccReviewRecord reviewRecord = (TAccReviewRecord) objectMessage.getObject(); 12 ,,, 13 } catch (final Exception e) { 14 logger.error("[佇列發送]同步落地服務公司充值資訊發送失敗", e); 15 } 16 } 17 } 18 }
activemq producer(服務A)存放json串后,activemq consumer(服務B) 改造后:
1 @Component("commonSyncMQService") 2 public class CommonSyncMQService implements MessageListener { 3 private final static Logger logger = LoggerFactory.getLogger(CommonSyncMQService.class); 4 @Autowired 5 private SyncAccReviewRecordService syncAccReviewRecordService; 6 7 @Override 8 public void onMessage(Message message) { 9 if (message instanceof ObjectMessage) { 10 final ObjectMessage objectMessage = (ObjectMessage) message; 11 try { 12 logger.info("同步落地服務公司充值資訊介面訊息佇列接收引數[{}]",objectMessage.getObject()); 13 TAccReviewRecord reviewRecord = JSONObject.parseObject(String.valueOf(objectMessage.getObject()),TAccReviewRecord.class); 14 ,,, 15 } catch (final Exception e) { 16 logger.error("[佇列發送]同步落地服務公司充值資訊發送失敗", e); 17 } 18 } 19 } 20 }
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/248414.html
標籤:其他
上一篇:掃描指定注解獲取其相關屬性
