最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳細(xì)聊聊RabbitMQ竟無(wú)法反序列化List問(wèn)題

 更新時(shí)間:2021年09月18日 09:52:16   作者:不一樣的科技宅  
這篇文章主要給大家介紹了關(guān)于RabbitMQ竟無(wú)法反序列化List的相關(guān)資料,文中通過(guò)示例代碼將問(wèn)題以及解決的過(guò)程介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

前言

最近在接到了一個(gè)需求,大概是通過(guò)RabbitMq給xx子系統(tǒng)同步用戶數(shù)據(jù),要提供單個(gè)同步和批量同步。內(nèi)心暗喜這不簡(jiǎn)單的很嘛。三下五除二就把代碼給寫完了,大概長(zhǎng)這樣:

public void syncUserSingle(User user) {
    // 省略一大堆業(yè)務(wù)代碼
    rabbitTemplate.convertAndSend("q_sync_user_single", user);
}

public void syncUserBatch(List<User> userList) {
    // 省略一大堆業(yè)務(wù)代碼
    rabbitTemplate.convertAndSend("q_sync_user_batch", userList);
}

但是在聯(lián)調(diào)的過(guò)程中,遇到了一個(gè)比較奇葩的問(wèn)題。單個(gè)用戶進(jìn)行同步時(shí),子系統(tǒng)可以正常消費(fèi)。然后進(jìn)行批量同步的時(shí)候,子系統(tǒng)報(bào)錯(cuò)了。并拋出java.lang.ClassCastException提示 LinkedHashMap cannot xxxx class 。于是負(fù)責(zé)子系統(tǒng)的哥們笑嘻嘻的(表面笑嘻嘻)走過(guò)來(lái)對(duì)我說(shuō),不是約定List 為啥發(fā)個(gè)Map過(guò)來(lái)?

看到這個(gè)錯(cuò)誤,著實(shí)讓我摸不到頭腦。頓時(shí)一堆疑問(wèn)涌上心頭, 為啥單個(gè)對(duì)象可以,List就不行呢?我發(fā)的是List 數(shù)據(jù),為啥變成Map了?雖然一大堆疑問(wèn),但是只能笑嘻嘻的說(shuō),我檢查一下哈。

問(wèn)題重現(xiàn)

項(xiàng)目依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/>
    </parent>
    <!-- 省略部分信息 -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
    </dependencies>
</project>

發(fā)送方

初始化隊(duì)列

@Configuration
public class QueueConfig {
    @Bean
    public Queue test() {
        return new Queue("test");
    }
}

配置RabbitTemplete

@Configuration
public class RabbitTemplateConfig {
    @Autowired
    public RabbitTemplateConfig(RabbitTemplate rabbitTemplate) {
        // 設(shè)置Json消息轉(zhuǎn)換器
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
    }
}

發(fā)送接口

@Controller
@RequestMapping("/test")
public class TestController {

    @Resource
    private RabbitTemplate template;

    @GetMapping("/send")
    public void send() {
        template.convertAndSend("test", Collections.singletonList(new User(20, "不一樣的科技宅")));
    }
}

User類

@Data
@AllArgsConstructor
public class User {
    /**
     * 年齡
     */
    private Integer age;

    /**
     * 姓名
     */
    private String name;
}

接收方

監(jiān)聽(tīng)配置

@Configuration
public class RabbitListenerConfig {

    @Bean
    public SimpleRabbitListenerContainerFactory customFactory(SimpleRabbitListenerContainerFactoryConfigurer configurer,
                                                              ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        // 設(shè)置消息轉(zhuǎn)換器
        factory.setMessageConverter(new Jackson2JsonMessageConverter());
        configurer.configure(factory, connectionFactory);
        return factory;
    }

}

接收方

@Service
public class UserService {

    public void save(List<User> userList) {
        userList.forEach(System.out::println);
    }
    
}
@Componentpublic class Receiver {    @Resource    private UserService userService;    @RabbitListener(queues = "test", containerFactory = "customFactory")    public void receive(@Payload List<User> msg) {        userService.save(msg);    }}

錯(cuò)誤日志

❝好家伙果然失敗了,這百分百必現(xiàn)的bug呀。❞

分析問(wèn)題原因

首先錯(cuò)誤信息是在消費(fèi)端拋出來(lái)的,按理應(yīng)該是消費(fèi)端出問(wèn)題概率較大。但是如果和他說(shuō)的一樣,我生產(chǎn)端發(fā)送的消息就是錯(cuò)誤的,從而導(dǎo)致消費(fèi)端出問(wèn)題呢?這對(duì)這個(gè)疑問(wèn),我先斷開(kāi)消費(fèi)端,然后發(fā)送一條消息,并通過(guò)Rabbitmq的管控臺(tái)來(lái)查看消息的內(nèi)容是否正確。

消息內(nèi)容如下圖所示:

通過(guò)上圖可以發(fā)現(xiàn),消息體(payload)是一個(gè)標(biāo)準(zhǔn)的json串,并且TypeId也是List,并不是錯(cuò)誤信息中的LinkedHashMap。哈哈哈,到此可以石錘是消費(fèi)端反序列化的問(wèn)題了。趕緊把鍋甩出去,抽他呀的(自嗨而已),我寫的代碼怎么可能有bug。

對(duì)我愛(ài)學(xué)習(xí)的我,肯定不愿意就這樣算了。必須刨根問(wèn)底,給他上一課。于是我在google一圈發(fā)現(xiàn)這竟然是這個(gè)bug。有個(gè)老哥也發(fā)現(xiàn)了,并提交了一個(gè)issues: spring-ampq/issues/1279。

大致是說(shuō):嘗試從 Spring Boot 2.3.1 升級(jí)到 2.3.3,然后再升級(jí)到 2.3.6。錯(cuò)誤信息依然是:List<Foo> foos是LikedHashMap,而不是Foo對(duì)象。并通過(guò)遠(yuǎn)程調(diào)試確認(rèn)了這種情況。出于某種原因,他認(rèn)為沒(méi)有正確使用泛型類型?;謴?fù)到 Spring-AMQP 2.2.7 使它再次工作,并且對(duì)象確實(shí)是Foo。

然后garyrussell這個(gè)人說(shuō):他們添加了對(duì)抽象類反序列化的支持,如果配置不正確,這會(huì)對(duì)消息轉(zhuǎn)換器產(chǎn)生一些副作用。然后調(diào)查了一下,確認(rèn)這是一個(gè)錯(cuò)誤。是由于List是抽象的,新代碼認(rèn)為它不能反序列化。

解決方法是:

converter.setAlwaysConvertToInferredType(true);

后面還提到在 GH-1729: Fix JSON Regression修復(fù)這個(gè)問(wèn)題,修復(fù)的代碼如下:

通過(guò)閱讀代碼發(fā)現(xiàn),修改前的邏輯是: 如果推斷類型是抽象的,則返回false也就代表不能轉(zhuǎn)換成推斷類型。然后被轉(zhuǎn)換成LinkedHashMap。這也就是出現(xiàn) LinkedHashMap cannot cast xxxx class的主要原因。

修改后變成了:如果推斷類型是抽象的并且不是容器類型,返回false。也就意味著,雖然推斷類型是抽象的,但是如果是容器類型,并且容器內(nèi)的對(duì)象不是抽象的,則可以被轉(zhuǎn)換。這樣一來(lái)避免了上述問(wèn)題的產(chǎn)生了。

前面還提到了通過(guò)增加配置來(lái)解決。解決起來(lái)就相對(duì)簡(jiǎn)單粗暴了,始終轉(zhuǎn)換推斷類型。

解決辦法

到此問(wèn)題分析完畢,簡(jiǎn)單總結(jié)一下解決方法。主要有兩種:

1、在消費(fèi)端開(kāi)啟如下配置即可:

// 始終轉(zhuǎn)換推斷類型
converter.setAlwaysConvertToInferredType(true);

2、升級(jí)版本:由于GH-1729: Fix JSON Regression合并到了2.2.13.RELEASE。所以只需要將 spring-amqp 升級(jí)到 2.2.13.RELEASE 或以上。或者升級(jí)SpringBoot版本到2.3.7.RELEASE。

總結(jié)

到此這篇關(guān)于RabbitMQ竟無(wú)法反序列化List的文章就介紹到這了,更多相關(guān)RabbitMQ無(wú)法反序列化List內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用Mybatis Plus整合多數(shù)據(jù)源和讀寫分離的詳細(xì)過(guò)程

    使用Mybatis Plus整合多數(shù)據(jù)源和讀寫分離的詳細(xì)過(guò)程

    這篇文章主要介紹了Mybatis Plus整合多數(shù)據(jù)源和讀寫分離的詳細(xì)過(guò)程,mybatisplus可以整合阿里的分布式事務(wù)組件seata,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2021-09-09
  • Java實(shí)現(xiàn)的計(jì)算稀疏矩陣余弦相似度示例

    Java實(shí)現(xiàn)的計(jì)算稀疏矩陣余弦相似度示例

    這篇文章主要介紹了Java實(shí)現(xiàn)的計(jì)算稀疏矩陣余弦相似度功能,涉及java基于HashMap的數(shù)值計(jì)算相關(guān)操作技巧,需要的朋友可以參考下
    2018-07-07
  • Java 添加和刪除PDF圖層的示例代碼

    Java 添加和刪除PDF圖層的示例代碼

    本文將介紹如何使用Spire.PDF for Java來(lái)添加和刪除PDF圖層,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2020-02-02
  • Mybatis的collection三層嵌套查詢方式(驗(yàn)證通過(guò))

    Mybatis的collection三層嵌套查詢方式(驗(yàn)證通過(guò))

    這篇文章主要介紹了Mybatis的collection三層嵌套查詢方式(驗(yàn)證通過(guò)),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • 說(shuō)說(shuō)Java異步調(diào)用的幾種方式

    說(shuō)說(shuō)Java異步調(diào)用的幾種方式

    本文主要介紹了說(shuō)說(shuō)Java異步調(diào)用的幾種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Java中的JSONObject使用方法和常用操作

    Java中的JSONObject使用方法和常用操作

    本文詳細(xì)介紹了Java中JSONObject的使用方法,包括創(chuàng)建、基本操作、高級(jí)特性和錯(cuò)誤處理,通過(guò)示例代碼和解釋,幫助開(kāi)發(fā)者更好地理解和使用JSONObject來(lái)處理JSON數(shù)據(jù),感興趣的朋友一起看看吧
    2025-02-02
  • java 實(shí)現(xiàn)音樂(lè)播放器的簡(jiǎn)單實(shí)例

    java 實(shí)現(xiàn)音樂(lè)播放器的簡(jiǎn)單實(shí)例

    這篇文章主要介紹了java 實(shí)現(xiàn)音樂(lè)播放器的簡(jiǎn)單實(shí)例的相關(guān)資料,希望通過(guò)本文能幫助到大家,實(shí)現(xiàn)這樣的功能,需要的朋友可以參考下
    2017-09-09
  • Java中properties文件中的中文亂碼問(wèn)題

    Java中properties文件中的中文亂碼問(wèn)題

    Properties為了方便用戶的配置,用于讀取Java的配置文件,不同的編程語(yǔ)言有自己所支持的配置文件,能讓用戶夠脫離程序本身去修改相關(guān)的變量設(shè)置,這篇文章主要介紹了Java中properties文件中的中文亂碼問(wèn)題,需要的朋友可以參考下
    2023-08-08
  • Java面向?qū)ο筇匦陨钊肱傥龇庋b

    Java面向?qū)ο筇匦陨钊肱傥龇庋b

    封裝是一個(gè)非常廣泛的概念,小到一個(gè)屬性的封裝,大到一個(gè)框架或者一個(gè)項(xiàng)目的封裝,下面這篇文章主要給大家介紹了關(guān)于java中封裝的那點(diǎn)事,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-05-05
  • Java?中的?switch?語(yǔ)句:類型支持與限制詳解

    Java?中的?switch?語(yǔ)句:類型支持與限制詳解

    Java?中的?switch?語(yǔ)句是一種強(qiáng)大的多分支選擇結(jié)構(gòu),它支持多種數(shù)據(jù)類型,包括基本數(shù)據(jù)類型、字符串和枚舉類型,本文給大家介紹Java?中的?switch?語(yǔ)句:類型支持與限制,感興趣的朋友一起看看吧
    2024-08-08

最新評(píng)論

丰都县| 宜城市| 扎鲁特旗| 京山县| 鄂伦春自治旗| 河南省| 延津县| 金山区| 九江县| 赤峰市| 汝城县| 宜兴市| 那坡县| 常山县| 兴业县| 海丰县| 新疆| 株洲市| 新河县| 阿克陶县| 黔江区| 保山市| 汝城县| 蒙山县| 铁岭县| 营山县| 庆阳市| 皋兰县| 清涧县| 长沙县| 黑龙江省| 安丘市| 桃园县| 泰和县| 泰宁县| 西贡区| 鄂尔多斯市| 龙门县| 师宗县| 兴隆县| 建始县|