欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JSON.toJSONString使用異常分析

 更新時(shí)間:2023年09月11日 15:36:29   作者:土豆肉絲蓋澆飯  
這篇文章主要為大家介紹了JSON.toJSONString使用異常分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

先說(shuō)說(shuō)坑

JSON.toString在序列化對(duì)象時(shí),默認(rèn)通過(guò)的是get*()方法來(lái)查找屬性,而不是具體某個(gè)屬性,同時(shí)回忽略transient注解的屬性。

測(cè)試案例如下

public class FastJsonTest {
    public static void main(String[] args) {
        Person person = new Person();
        person.setBirth(new Date());
        System.out.println(JSON.toJSONString(person));
    }
    public static class Person{
        private Integer age =123;
        private transient Date birth;
        public Date getBirth() {
            return birth;
        }
        public void setBirth(Date birth) {
            this.birth = birth;
        }
        public String getName(){
            return "scj";
        }
    }
}

輸出

{"name":"scj"}

問(wèn)題發(fā)生

最近在迭代一個(gè)老項(xiàng)目,升級(jí)中間件框架版本(不升級(jí)不給打包部署)后,在項(xiàng)目啟動(dòng)的時(shí)候居然拋出以下異常

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.masaike.yama.platform.domain.model.product.ProductServiceEntity.properties, could not initialize proxy - no Session
    at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:582)
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:201)
    at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:145)
    at org.hibernate.collection.internal.PersistentBag.size(PersistentBag.java:261)
    at com.masaike.yama.platform.infrastructure.converter.ProductServiceConverterImpl.productServicePropertyVOListToProductServicePropertyDTOList(ProductServiceConverterImpl.java:139)
    at com.masaike.yama.platform.infrastructure.converter.ProductServiceConverterImpl.map(ProductServiceConverterImpl.java:50)
    at com.masaike.yama.platform.infrastructure.converter.ProductServiceConverterImpl.entityListToDTOList(ProductServiceConverterImpl.java:32)
    at com.masaike.yama.platform.query.ProductServiceQueryServiceImpl.getAllProductService(ProductServiceQueryServiceImpl.java:43)
    at com.alibaba.fastjson.serializer.ASMSerializer_12_ProductServiceQueryServiceImpl.write(Unknown Source)
    at com.alibaba.fastjson.serializer.JSONSerializer.writeWithFieldName(JSONSerializer.java:333)
    at com.alibaba.fastjson.serializer.ASMSerializer_1_InterfaceInfo.write(Unknown Source)
    at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:285)
    at com.alibaba.fastjson.JSON.toJSONString(JSON.java:745)
    at com.alibaba.fastjson.JSON.toJSONString(JSON.java:683)
    at com.alibaba.fastjson.JSON.toJSONString(JSON.java:648)
    at com.alibaba.dubbo.config.masaikehttp.ExportedInterfaceManager.addInterface(ExportedInterfaceManager.java:104)//關(guān)鍵點(diǎn)
    at com.alibaba.dubbo.config.ServiceConfig.doExport(ServiceConfig.java:321)
    at com.alibaba.dubbo.config.ServiceConfig.export(ServiceConfig.java:218)
    at com.alibaba.dubbo.config.spring.ServiceBean.onApplicationEvent(ServiceBean.java:123)
    at com.alibaba.dubbo.config.spring.ServiceBean.onApplicationEvent(ServiceBean.java:49)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:400)
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:354)
    at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:886)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:161)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:386)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1242)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1230)
    at com.masaike.yama.bootstrap.BootStrapApplication.main(BootStrapApplication.java:36)

這個(gè)一個(gè)使用JPA時(shí)常見(jiàn)問(wèn)題:延遲加載的時(shí)候session不存在

關(guān)于延遲加載no-session問(wèn)題,可以看如何解決JPA延遲加載no Session報(bào)錯(cuò)

從日志定位到拋出異常的方法為

@Override
@Transactional(rollbackFor = Exception.class)
public List<XXDTO> getAllXX() {
    List<XXEntity> result = xXQueryRepository.findAll();
    //下面的converter會(huì)觸發(fā)延遲加載
    return XXConverter.INSTANCE.entityListToDTOList(result);
}

這邊存在兩個(gè)迷惑性行為

  • 啟動(dòng)的時(shí)候怎么調(diào)用了getAllXX方法
  • getAllXX我加了@Transactional,理論上是有session的

問(wèn)題排查

精簡(jiǎn)上面的異常棧

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.masaike.yama.platform.domain.model.product.ProductServiceEntity.properties, could not initialize proxy - no Session
    at com.masaike.yama.platform.infrastructure.converter.ProductServiceConverterImpl.productServicePropertyVOListToProductServicePropertyDTOList(ProductServiceConverterImpl.java:139)
    at com.masaike.yama.platform.infrastructure.converter.ProductServiceConverterImpl.map(ProductServiceConverterImpl.java:50)
    at com.masaike.yama.platform.infrastructure.converter.ProductServiceConverterImpl.entityListToDTOList(ProductServiceConverterImpl.java:32)
    at com.masaike.yama.platform.query.ProductServiceQueryServiceImpl.getAllProductService(ProductServiceQueryServiceImpl.java:43)
    at com.alibaba.fastjson.JSON.toJSONString(JSON.java:648)
    at com.alibaba.dubbo.config.masaikehttp.ExportedInterfaceManager.addInterface(ExportedInterfaceManager.java:104)//關(guān)鍵點(diǎn)
    at com.alibaba.dubbo.config.ServiceConfig.doExport(ServiceConfig.java:321)
    at com.alibaba.dubbo.config.ServiceConfig.export(ServiceConfig.java:218)

可以復(fù)盤(pán)出問(wèn)題發(fā)生的現(xiàn)場(chǎng)

dubbo服務(wù)進(jìn)行export的時(shí)候調(diào)用了ExportedInterfaceManager.addInterface方法,而在addInterface方法中調(diào)用的JSON.toJSONString方法觸發(fā)了ProductServiceQueryServiceImpl.getAllProductService方法

在看了ExportedInterfaceManager.addInterface源碼之后,問(wèn)題的起因浮出水面

ExportedInterfaceManager這個(gè)類(lèi)是用來(lái)針對(duì)接口暴露http服務(wù)時(shí)收集元數(shù)據(jù)使用

public synchronized void addInterface(Class<?> interfaceCls, Object obj) {
    //如果是代理類(lèi)獲取代理類(lèi)對(duì)象
    obj = getObjectTarget(obj);//獲取原始對(duì)象
    //...
    InterfaceInfo interfaceInfo = new InterfaceInfo();
    interfaceInfo.setInterfaceName(interfaceName);
    interfaceInfo.setRef(obj);//致命之處
    //...
    logger.info(String.format("start to addInterface into interfaceMap,interfaceName[%s],interfaceInfo[%s]",interfaceName, JSON.toJSONString(interfaceInfo)));//致命之處
    // add interface info to map
    interfaceMap.put(interfaceName, interfaceInfo);
}

對(duì)于第一個(gè)問(wèn)題,InterfaceInfo的ref指向ProductServiceQueryServiceImpl,在打印日志的時(shí)候,JSON.toJSONString觸發(fā)了ProductServiceQueryServiceImpl中的get方法

而對(duì)于第二個(gè)問(wèn)題,obj = getObjectTarget(obj);這段代碼會(huì)獲取代理的原始對(duì)象,導(dǎo)致事務(wù)失效。

問(wèn)題危害

拋開(kāi)獲取原始對(duì)象這個(gè)邏輯不說(shuō),這個(gè)bug的致命之處在于,他會(huì)調(diào)用所暴露dubbo接口中所有get*()格式的方法

問(wèn)題解決

解決方式很簡(jiǎn)單,有以下兩種

  • 不要序列化ref(加fastjson注解或字段加transient)
  • 去掉打印日志邏輯

在反饋這個(gè)問(wèn)題后,中間件團(tuán)隊(duì)的改動(dòng)如下

以上就是JSON.toJSONString使用異常分析的詳細(xì)內(nèi)容,更多關(guān)于JSON.toJSONString異常的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java解析xml之jdom解析xml示例分享

    java解析xml之jdom解析xml示例分享

    JDOM是專(zhuān)門(mén)為Java打造的API,JDOM采用了Java中的Collection架構(gòu)來(lái)封裝集合,是Java愛(ài)好者更加熟悉的模式,下面看使用示例
    2014-01-01
  • SpringBoot項(xiàng)目如何添加2FA雙因素身份認(rèn)證

    SpringBoot項(xiàng)目如何添加2FA雙因素身份認(rèn)證

    雙因素身份驗(yàn)證2FA是一種安全系統(tǒng),要求用戶提供兩種不同的身份驗(yàn)證方式才能訪問(wèn)某個(gè)系統(tǒng)或服務(wù),國(guó)內(nèi)普遍做短信驗(yàn)證碼這種的用的比較少,不過(guò)在國(guó)外的網(wǎng)站中使用雙因素身份驗(yàn)證的還是很多的,這篇文章主要介紹了SpringBoot項(xiàng)目如何添加2FA雙因素身份認(rèn)證,需要的朋友參考下
    2024-04-04
  • 詳解SpringBoot封裝使用JDBC

    詳解SpringBoot封裝使用JDBC

    這篇文章主要介紹了SpringBoot封裝JDBC使用教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-12-12
  • Java 中的 BufferedReader 介紹_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java 中的 BufferedReader 介紹_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    BufferedReader 是緩沖字符輸入流。它繼承于Reader。接下來(lái)通過(guò)本文給大家介紹BufferedReader的相關(guān)知識(shí),需要的朋友參考下吧
    2017-05-05
  • Java設(shè)計(jì)模式之橋模式(Bridge模式)介紹

    Java設(shè)計(jì)模式之橋模式(Bridge模式)介紹

    這篇文章主要介紹了Java設(shè)計(jì)模式之橋模式(Bridge模式)介紹,本文講解了為什么使用橋模式、如何實(shí)現(xiàn)橋模式、Bridge模式在EJB中的應(yīng)用等內(nèi)容,需要的朋友可以參考下
    2015-03-03
  • Java同步代碼塊和同步方法原理與應(yīng)用案例詳解

    Java同步代碼塊和同步方法原理與應(yīng)用案例詳解

    這篇文章主要介紹了Java同步代碼塊和同步方法原理與應(yīng)用,結(jié)合具體案例形式分析了使用java同步代碼塊和同步方法實(shí)現(xiàn)買(mǎi)票功能的相關(guān)原理與操作技巧,需要的朋友可以參考下
    2019-10-10
  • 一文深入解析JDBC超時(shí)機(jī)制

    一文深入解析JDBC超時(shí)機(jī)制

    恰當(dāng)?shù)腏DBC超時(shí)設(shè)置能夠有效地減少服務(wù)失效的時(shí)間,下面這篇文章主要給大家介紹了關(guān)于JDBC超時(shí)機(jī)制的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-10-10
  • 探討Java中的深淺拷貝問(wèn)題

    探討Java中的深淺拷貝問(wèn)題

    這個(gè)概念估計(jì)懂C++的人不會(huì)陌生,但是很多朋友并不了解,概括起來(lái)將淺拷貝就是指兩個(gè)對(duì)象公用一個(gè)值,一個(gè)的改變了另一個(gè)也會(huì)隨之改變,深拷貝則是兩個(gè)對(duì)象值相等,但是相互獨(dú)立互不影響。下面我們將關(guān)于java的淺拷貝和深拷貝做一個(gè)詳細(xì)講解
    2021-06-06
  • java maven項(xiàng)目如何讀取配置文件信息

    java maven項(xiàng)目如何讀取配置文件信息

    這篇文章主要介紹了java maven項(xiàng)目如何讀取配置文件信息,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Servlet開(kāi)發(fā)JavaWeb工程示例詳解

    Servlet開(kāi)發(fā)JavaWeb工程示例詳解

    這篇文章主要介紹了Servlet開(kāi)發(fā)JavaWeb工程示例詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07

最新評(píng)論