我正在尝试基于 Spring Boot 3 构建 Web 应用程序,并计划将其作为本机映像在 Kubernetes 中运行。所以我的目标是构建原生图像,但这是我在这里遇到 Feign 问题的地方。
我的应用程序使用 Feign 客户端访问第三方 API。
应用程序在非本机模式下作为纯 Java 应用程序运行时完美运行。但是一旦我在 Docker 中将它作为本机映像运行,它就无法进行第三方调用,因为请求/响应 DTO 类型在本机运行时不可用,迫使 Jackson 抛出错误:
Cannot construct instance of `com.steam.trading.trade.bot.client.steam.dto.SteamResponse`: cannot deserialize from Object value (no delegate- or property-based Creator): this appears to be a native image, in which case you may need to configure reflection for the class that is to be deserialized
我从这个错误中了解到,没有为 Feign Client 请求/响应 dto 数据类型创建 AOT 序列化提示。列出所有序列化类也不是一个选项,因为这将是大量的手工工作,而且很容易遗漏那里的东西。
问题是,这是 Open Feign 中的某种错误,是否有开箱即用的
RuntimeHintsRegistrar
导入还是我应该自己注册所有 DTO?
我正在使用 Spring Cloud 依赖项中的 Spring Boot 3 和 OpenFeign。版本是:
<spring-boot.version>3.0.4</spring-boot.version>
<spring-cloud.version>2022.0.1</spring-cloud.version>
我有以下Feign客户:
@FeignClient(name = "steam-server-time-api", url = "${app.steam.api}", configuration = FeignSteamConfiguration.class)
public interface ServerTimeClient {
@RequestLine("POST /ITwoFactorService/QueryTime/v1/")
SteamResponse<QueryTime> getServerTime();
}
以下假装配置:
public class FeignSteamConfiguration {
@Bean
public Contract useFeignAnnotations() {
return new Contract.Default();
}
@Bean
public Encoder feignFormEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
return new FormEncoder(new SpringEncoder(messageConverters));
}
@Bean
public ErrorDecoder clientErrorDecoder() {
return new CustomErrorDecoder();
}
}
我尝试了默认和 Spring Contracts,但问题是一样的。
我正在使用命令构建图像:
mvn -Pnative spring-boot:build-image
我尝试使用 RegisterReflectionForBinding 手动注册,但是拥有 50 多个类并不是手动列出所有类的好办法。 我也尝试切换 Default 和 Spring 合同,但问题仍然相同。
一些做对象序列化/反序列化的库(比如Jackson)不知道如何在spring native的运行时做这个,所以你应该告诉/注册到spring native关于代理类,资源文件/路径,反射方法,或要序列化/反序列化的对象。
所以我相信您需要创建一个实现
RuntimeHintsRegistrar
接口的类,并设置您需要序列化/反序列化的类,如以下链接所述:https://docs.spring .io/spring-boot/docs/current/reference/html/native-image.html#native-image.advanced.custom-hints(spring native 自定义提示)
或在某些配置类中注释以下注释:
@RegisterReflectionForBinding({YourCustomObject.class})
您面临的问题是由于 AOT 序列化提示不是为 Feign 客户端请求/响应 DTO 数据类型创建的,这在本机运行时不可用。这会导致 Jackson 在尝试反序列化响应时抛出错误。
您可以尝试使用几个选项来解决此问题。一种选择是使用 Spring Native 项目提供的 @RegisterForReflection 注释来注册 DTO 类以进行反射。您可以将此注释添加到导致问题的每个 DTO 类,它应该可以解决问题。
另一种选择是使用Spring Native 项目提供的@NativeHint 注解为DTO 类配置AOT 序列化提示。此注释允许您为特定类和字段配置提示,并且应该用于注册 DTO 类以进行序列化。
也可以尝试使用Spring Native提供的@AutoConfigureJson注解,自动注册所有DTO类,使用Jackson进行序列化
此外,您可能需要考虑使用支持原生图像编译的不同序列化/反序列化库,例如 Protobuf 或 Avro。这些库可以自动生成所需的序列化提示,并且可能比使用原生图像的 Jackson 更容易使用。
总的来说,针对您的特定用例的最佳解决方案将取决于您的 DTO 类的复杂性和您需要对序列化/反序列化过程的控制级别。