Feign如何使用protobuf的类作为参数调用

 更新时间:2022年03月17日 09:58:00   作者:宝贝等等我  
这篇文章主要介绍了Feign如何使用protobuf的类作为参数调用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

这两天在把原来的项目迁移到spring cloud上,微服务之间的数据传输使用protobuf。

码了几天的代码。重要准备上线测试下微服务之间的接口调用功能,但是在用feign调用数据库代理接口时,总是报一个错误,在这记录下。

feign客户端接口定义如下

@FeignClient(name = "db-proxy")
public interface RemoteRestFull {
    @RequestMapping(value = "/getUser")
    User.UserInfoRsp getUserInfo(@RequestBody User.UserInfoReq req);
}

服务端接口实现如下

@RestController
public class UserRestFull {
    @RequestMapping("/getUser")
    public User.UserInfoRsp getUserInfo(@RequestBody User.UserInfoReq req) {
        .......
    }
}

服务端具体代码实现就省略了。

服务启动后,使用测试代码测试连接,发送消息。

在feign接口调用时

出现下面的错误:

因为涉及到具体的类报错,省略了一些信息。。。

[WARN ][2021-01-04 14:10:38][DefaultChannelPipeline.java:1152]:onUnhandledInboundException - An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
feign.codec.EncodeException: Error converting request body
        at org.springframework.cloud.openfeign.support.SpringEncoder.encode(SpringEncoder.java:119) ~[spring-cloud-openfeign-core-2.2.5.RELEASE.jar!/:2.2.5.RELEASE]
        at org.springframework.cloud.openfeign.support.PageableSpringEncoder.encode(PageableSpringEncoder.java:101) ~[spring-cloud-openfeign-core-2.2.5.RELEASE.jar!/:2.2.5.RELEASE]
        at feign.ReflectiveFeign$BuildEncodedTemplateFromArgs.resolve(ReflectiveFeign.java:380) ~[feign-core-10.10.1.jar!/:?]
        at feign.ReflectiveFeign$BuildTemplateByResolvingArgs.create(ReflectiveFeign.java:232) ~[feign-core-10.10.1.jar!/:?]
        at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:84) ~[feign-core-10.10.1.jar!/:?]
        at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:100) ~[feign-core-10.10.1.jar!/:?]
        at com.sun.proxy.$Proxy93.getUser(Unknown Source) ~[?:?]
        ......................
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.handler.logging.LoggingHandler.channelRead(LoggingHandler.java:271) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.handlerRemoved(ByteToMessageDecoder.java:253) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:440) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.handler.logging.LoggingHandler.channelRead(LoggingHandler.java:271) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at java.lang.Thread.run(Thread.java:748) [?:1.8.0_231]
Caused by: org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.google.protobuf.UnknownFieldSet$Parser]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.google.protobuf.UnknownFieldSet$Parser and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: cn.nodetec.easychat.proto.IMUser$IMUserLogin["unknownFields"]->com.google.protobuf.UnknownFieldSet["parserForType"])
        at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:348) ~[spring-web-5.2.10.RELEASE.jar!/:5.2.10.RELEASE]
        at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:104) ~[spring-web-5.2.10.RELEASE.jar!/:5.2.10.RELEASE]
        at org.springframework.cloud.openfeign.support.SpringEncoder.checkAndWrite(SpringEncoder.java:176) ~[spring-cloud-openfeign-core-2.2.5.RELEASE.jar!/:2.2.5.RELEASE]
        at org.springframework.cloud.openfeign.support.SpringEncoder.encode(SpringEncoder.java:109) ~[spring-cloud-openfeign-core-2.2.5.RELEASE.jar!/:2.2.5.RELEASE]
        ... 46 more
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.google.protobuf.UnknownFieldSet$Parser and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: cn.nodetec.easychat.proto.IMUser$IMUserLogin["unknownFields"]->com.google.protobuf.UnknownFieldSet["parserForType"])
        at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1277) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:71) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:33) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1516) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:1006) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:342) ~[spring-web-5.2.10.RELEASE.jar!/:5.2.10.RELEASE]
        at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:104) ~[spring-web-5.2.10.RELEASE.jar!/:5.2.10.RELEASE]
        at org.springframework.cloud.openfeign.support.SpringEncoder.checkAndWrite(SpringEncoder.java:176) ~[spring-cloud-openfeign-core-2.2.5.RELEASE.jar!/:2.2.5.RELEASE]
        at org.springframework.cloud.openfeign.support.SpringEncoder.encode(SpringEncoder.java:109) ~[spring-cloud-openfeign-core-2.2.5.RELEASE.jar!/:2.2.5.RELEASE]
        ... 46 more

从log看,是AbstractJackson2HttpMessageConverter转换的问题,感谢度娘。让我找到了下面的解决方法。

这个问题主要是因为,feign的参数使用protobuf的类,在转换的时候,找不到Converter,如果是使用基本的数据类型是没有任何问题的。

所以,我们需要配置一个protobuf的HttpMessageConverter。

feign客户端增加一个配置如下

import feign.codec.Decoder;
import feign.codec.Encoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
 
@Configuration
public class ProtoFeignConfig {
    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverterObjectFactory;
 
    @Bean
    public ProtobufHttpMessageConverter protobufHttpMessageConverter() {
        return new ProtobufHttpMessageConverter();
    }
 
    @Bean
    public Encoder springEncoder() {
        return new SpringEncoder(this.messageConverterObjectFactory);
    }
 
    @Bean
    public Decoder springDecoder() {
        return new ResponseEntityDecoder(new SpringDecoder(this.messageConverterObjectFactory));
    }
}

服务端增加一个配置如下

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
 
@Configuration
public class ProtoFeignConfig {
    @Bean
    public ProtobufHttpMessageConverter protobufHttpMessageConverter() {
        return new ProtobufHttpMessageConverter();
    }
}

当然,pom中使用的是openfeign,依赖如下,注意

不要加入版本

否则编译报错:

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

这样就可以正常调用了。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • java读取证书公钥的实现

    java读取证书公钥的实现

    这篇文章主要介绍了java读取证书公钥的实现,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • 2020 IDEA安装教程与激活(idea2020激活码)

    2020 IDEA安装教程与激活(idea2020激活码)

    这篇文章主要介绍了2020 IDEA安装教程与激活(idea2020激活码),本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • Java 延时队列及简单使用方式详解

    Java 延时队列及简单使用方式详解

    这篇文章主要介绍了Java延时队列简单使用方式,通过本文学习知道延时队列是什么可以用来干什么,本文通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-08-08
  • IDEA配置MAVEN本地仓库的实现步骤

    IDEA配置MAVEN本地仓库的实现步骤

    本文主要介绍了IDEA配置MAVEN本地仓库的实现步骤,将详细介绍如何配置Maven环境变量,Maven配置文件,可以轻松地设置和配置MAVEN本地仓库,以便在IDEA中享受更高效的开发体验
    2023-08-08
  • 递归出现栈溢出stackoverflow的问题及解决

    递归出现栈溢出stackoverflow的问题及解决

    这篇文章主要介绍了关于递归出现栈溢出stackoverflow的问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • JAVA区间值判断[10,20)的实现

    JAVA区间值判断[10,20)的实现

    本文主要介绍了JAVA区间值判断[10,20)的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-09-09
  • Java实现验证码具体代码(图片、汉字)

    Java实现验证码具体代码(图片、汉字)

    这篇文章主要为大家详细介绍了Java实现验证码具体代码,包括图片验证码、汉字验证码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-01-01
  • 使用Java实现在PDF插入页眉页脚

    使用Java实现在PDF插入页眉页脚

    在处理PDF文档时,有时需要为文档中的每一页添加页眉和页脚,这篇文章主要为大家详细介绍了如何使用Java为PDF文件添加页眉、页脚,感兴趣的可以了解下
    2024-03-03
  • SpringSecurity表单配置之登录成功及页面跳转原理解析

    SpringSecurity表单配置之登录成功及页面跳转原理解析

    这篇文章主要介绍了SpringSecurity表单配置之登录成功及页面跳转原理解析,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2023-12-12
  • 详解FileInputStream读取文件数据的两种方式

    详解FileInputStream读取文件数据的两种方式

    这篇文章主要介绍了详解FileInputStream读取文件数据的两种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08

最新评论