Spring集成流程在Sping Boot 3.0.1更新后出现ClassCastException异常

v8wbuo2f  于 2023-03-02  发布在  Spring
关注(0)|答案(2)|浏览(216)

我正在进行Sping Boot 更新到3.0.1,以及Spring Integration 6.0.0和Spring Cloud Stream 4.0.0的升级。然而,在升级之后,我之前工作的Spring集成流程失败,并出现底层ClassCastException:

class org.springframework.messaging.handler.HandlerMethod$HandlerMethodParameter cannot be cast to class java.lang.reflect.Type (org.springframework.messaging.handler.HandlerMethod$HandlerMethodParameter is in unnamed module of loader 'app'; java.lang.reflect.Type is in module java.base of loader 'bootstrap')

**更新:**当尝试将对象conversionHint(在我的例子中为类型HandlerMethodParameter)强制转换为Type时,异常源于Spring云函数上下文内的JsonMessageConverter。

Cannot cast 'org.springframework.messaging.handler.HandlerMethod$HandlerMethodParameter' to 'java.lang.reflect.Type'
任何提示或建议,可能是什么问题是高度赞赏。
以下是受影响的集成流程和相应代码片段的高度简化版本以及更详细的说明:

@Bean
IntegrationFlow extract(SessionFactory<SftpClient.DirEntry> sftpSessionFactory,
                        XmlFileTransformer xmlFileTransformer){
   return IntegrationFlow
            .from(Sftp.inboundAdapter(sftpSessionFactory)
                    .preserveTimestamp(true)
                    .remoteDirectory("foo")
                    .regexFilter(".*\\.txt$")
                    .localDirectory(new File("sftp-inbound")), e -> e.id("sftpInboundAdapter")
                    .autoStartup(true)
                    .poller(Pollers.fixedDelay(5000))
            )
            .log(LoggingHandler.Level.DEBUG, "ExtractFlow", m -> "Successfully reached")
            .wireTap(MONITORING_FLOW)
            .log(LoggingHandler.Level.DEBUG, "ExtractFlow", m -> "Successfully done wire tap")
            .transform(xmlFileTransformer)
            .log(LoggingHandler.Level.DEBUG, "ExtractFlow", m -> "Successfully done transformation")
            .handle(m -> xmlProcessor.process((XmlFile) m.getPayload())
            .get();
}

@RequiredArgsConstructor
@Component
public class XmlFileTransformer implements GenericTransformer<Message<File>, XmlFile> {
   @Override
   public XmlFile transform(Message<File> message) {
       return new XmlFile(message.getPayload().toPath(), message.getHeaders().get("x-origin", String.class));
   }
}

来自窃听器的集成流再次通过实现GenericTransfomer(类似于编写为XmlFileTransformer)进行转换,然后使用Amqp.outboundAdapter发送消息。方法xmlProcessor.processXmlFile作为参数。但是,它从未到达实际方法,因为它在尝试通过窃听器时中断,如果我注解了尝试使用xmlfileTransformer转换时的线分接,则会断开。因此,在日志消息“成功到达”之后,会发生异常。
我正在使用以下相关依赖项(为了更好地概述,未列出其他使用的依赖项):

<dependencyManagement>
 <dependencies>
     <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>2022.0.0</version>
        <type>pom</type>
        <scope>import</scope>
     </dependency>
  </dependencies>
</dependencyManagement>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.0.1</version>
    <relativePath/>
</parent>

<dependencies>
   <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-stream</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.integration</groupId>
      <artifactId>spring-integration-sftp</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.integration</groupId>
      <artifactId>spring-integration-jdbc</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.integration</groupId>
      <artifactId>spring-integration-xml</artifactId>
   </dependency>
   <dependency>
     <groupId>org.springframework.integration</groupId>
      <artifactId>spring-integration-amqp</artifactId>
   </dependency>
</dependencies>

我检查了又检查了我的依赖项,以确保我没有任何旧的依赖项可能会与更新冲突。然而,这些应该是好的,因为我使用的主要是来自spring-boot-starter-parent的版本。
根据Spring Integration 6.0.0的迁移指南,不应该有任何我忘记处理的重大中断。我试图找到类似情况的任何信息,但似乎没有太多人尝试升级到Sping Boot 3,或者只是没有像我一样的问题。这可能是Spring Integration中的一个bug,或者我需要重构代码,以便它'它仍然在Spring Integration 6.0中运行吗?还是我忽略了依赖项的问题?

k0pti3hp

k0pti3hp1#

  • 免责声明,我不是在更新到Sping Boot 3,而是在编写一个使用Cloud Stream的新Spring Boot 3应用程序。与此新服务通信的其他服务仍在Spring Boot 2.3中 *

对于我(使用Sping Boot 3.0.2)来说,具有讽刺意味的是,错误是由消息发送到RMQ的方式引起的。在生产者端,我通过标准的RabbitTemplate而不是Spring的StreamBridge发送消息。
虽然我不完全熟悉Spring Cloud Steam的消息解码特性,但标准配置中的RabbitTemplate发送了一个base64编码的Java对象,包括它的package name
如果RabbitTemplate设置为使用JSON,也会出现这种情况,即

var eventPayload = new SomeEventDto(12332, "some string val", "another string val");
template.setMessageConverter(new Jackson2JsonMessageConverter());
    template.convertAndSend("rabbit-stream-exchange", "rabbit-stream-queue", eventPayload);

从上述代码发送消息会向rabbit消息添加额外的报头:

__TypeId__: com.example.example123.SomeEventDto

如果Spring Cloud Stream接收器接收到设置了__TypeId__头的消息,那么它将无法将消息转换为正确的对象,即使头被设置为应该反序列化的确切类型。同时,如果(手动)发送没有此头的相同负载,所有其他参数不变,则消息将被成功使用。
所以,我的办法是通过Spring Cloud涧传递信息:

@Service
@RequiredArgsConstructor
public class EventPublisher {
  private final StreamBridge streamBridge;

  public void sendSomeEvent(SomeEventDto event) throws IOException {
    streamBridge.send("some-event-binding-out-0", MessageBuilder.withPayload(event).build());
  }
}

The message sent this way was serialized as JSON and sent without the `__TypeId__` header which was confusing the consumer so much.
pw9qyyiw

pw9qyyiw2#

我为这个问题实施了一个变通方案。我发现ApplicationJsonMessageingMarshallingConverter()在Spring Cloud 4.0.x中由于不受欢迎而被移除。这个移除导致了这样一个事实,即每次我在IntegrationFlow中调用某种transform()时,消息都是用JsonMessageConverter转换的,其中实际的ClassCassException被非常正确地抛出。
考虑到我可以直接显式添加MappingJackson 2 MessageConverter,我尝试手动添加该bean,但该转换器未添加到要委托的“合格”消息转换器集中,因为它在ContentTypeConfiguration.java中的cloud-stream-config包中被过滤掉了。
但是,以下变通方案成功了:

public class CustomMessageMarshallingConverter extends MappingJackson2MessageConverter {}

然后将这个“自定义”转换器注册为bean:

@Bean
public MessageConverter customMessageConverter(){
   return new CustomMessageMarshallingConverter();
}

原始的MappingJackson 2 MessageConverter被添加到可用的消息转换器中,并正确地标识出此时实际上不需要转换。
这感觉像一个黑客,但我只是很高兴有工作代码。

相关问题