解决Fegin请求远程微服务时有几率出现时间解析异常: through reference chain: xxx->xxxDto[“xxxTime“]

先给大家推荐一个好玩的网站MyChatGPT(免梯子,国内直接用,不需要OpenAI账号):https://chat.icoding.ink/

异常场景

Spring Cloud + Alibaba

异常特征

当请求远程微服务时, 有一定几率产生时间对象解析失败. 通信框架使用fegin. 频繁请求时容易复现.

异常报文

2020-12-04 20:07:25.103 ERROR 1 --- [nio-9999-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is feign.codec.DecodeException: Error while extracting response for type [java.util.List<com.nhi.common.dto.HomeWorkDetailSectionDto>] and content type [application/json]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: For input string: "743E2.743E2"; nested exception is com.fasterxml.jackson.databind.JsonMappingException: For input string: "743E2.743E2" (through reference chain: java.util.ArrayList[0]->com.nhi.common.dto.HomeWorkDetailSectionDto["createTime"])] with root cause
java.lang.NumberFormatException: For input string: "743E2.743E2"
	at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043) ~[na:1.8.0_275]
	at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110) ~[na:1.8.0_275]
	at java.lang.Double.parseDouble(Double.java:538) ~[na:1.8.0_275]
	at java.text.DigitList.getDouble(DigitList.java:169) ~[na:1.8.0_275]
	at java.text.DecimalFormat.parse(DecimalFormat.java:2089) ~[na:1.8.0_275]
	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2162) ~[na:1.8.0_275]
	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514) ~[na:1.8.0_275]
	at java.text.DateFormat.parse(DateFormat.java:364) ~[na:1.8.0_275]
	at com.nhi.common.config.DateFormatConfig$DateJsonDeserializer.deserialize(DateFormatConfig.java:47) ~[en-common-0.0.1-SNAPSHOT.jar!/:0.0.1-SNAPSHOT]
	.....

异常分析

最终定位到类com.nhi.common.config.DateFormatConfig, 该类是我在项目中写的一个全局时间格式化个配置类. 用于统一微服务通信和前后端通信时的Date对象的格式.
代码如下:

package com.nhi.common.config;

import com.fasterxml.*;
import java.text.*;
import java.io.IOException;
import java.util.Date;


/**
 * @Author: 郭胜凯
 * @Date: 2019-06-11 11:36
 * @Email 719348277@qq.com
 * @Description: 全局Rest full API Date类型JSON 格式化
 */
@JsonComponent
public class DateFormatConfig {

	/**
	 * 时间解析器
	 */
	final static SimpleDateFormat DF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 日期格式化
     */
    public static class DateJsonSerializer extends JsonSerializer<Date> {
        @Override
        public void serialize(Date date, JsonGenerator jsonGenerator,
                              SerializerProvider serializerProvider) throws IOException {
            jsonGenerator.writeString(DF.format(date));
        }
    }

    /**
     * 解析日期字符串
     */
    public static class DateJsonDeserializer extends JsonDeserializer<Date> {
        @Override
        public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
                throws IOException, JsonProcessingException {
            try {
                return DF.parse(jsonParser.getText());
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

根据异常报文, 可以确定异常发生在DF.parse(jsonParser.getText());这句代码中, 远程服务的时间传值正常, 本地微服务解析时有几率报错.

产生原因

期初为了提升性能, 减少重复创建SimpleDateFormat对象, 我将其实例放到了全局静态表中. 但这个对象线程不安全, 当并发请求时, 由于多个线程同时使用其实例会出现线程安全问题.

解决方案

将全局的SimpleDateFormat对象放到方法内部, 每个线程使用私有的实例, 修改后的代码如下:

package com.nhi.common.config;

import com.fasterxml.*;
import java.text.*;
import java.io.IOException;
import java.util.Date;

/**
 * @Author: 郭胜凯
 * @Date: 2019-06-11 11:36
 * @Email 719348277@qq.com
 * @Description: 全局Rest full API Date类型JSON 格式化
 */
@JsonComponent
public class DateFormatConfig {

    /**
     * 日期格式化
     */
    public static class DateJsonSerializer extends JsonSerializer<Date> {
        @Override
        public void serialize(Date date, JsonGenerator jsonGenerator,
                              SerializerProvider serializerProvider) throws IOException {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            jsonGenerator.writeString(dateFormat.format(date));
        }
    }

    /**
     * 解析日期字符串
     */
    public static class DateJsonDeserializer extends JsonDeserializer<Date> {
        @Override
        public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
                throws IOException, JsonProcessingException {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            try {
                return dateFormat.parse(jsonParser.getText());
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

参考资料

https://medium.com/@daveford/numberformatexception-multiple-points-when-parsing-date-650baa6829b6

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值