观察参数类型不匹配 Spring Amqp Remoting With Kotlin

Observing argument type mismatch Spring Amqp Remoting With Kotlin

虽然服务只有 1 个参数,但在将 spring 与 kotlin 组合使用时,我总是遇到参数不匹配。 我也调试过 org.springframework.remoting.support.RemoteInvocation.invoke 方法 我可以看到它正好传递了 1 个参数和正确的 targetObject。但是invoke(targetObject, this.arguments);导致参数不匹配。

源代码:

https://github.com/c-nnooka/RabbitMqRemotingKotlin

异常

Caused by: **java.lang.Throwable: argument type mismatch**
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_161]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_161]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_161]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_161]
    at org.springframework.remoting.support.RemoteInvocation.invoke(RemoteInvocation.java:215) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at org.springframework.remoting.support.DefaultRemoteInvocationExecutor.invoke(DefaultRemoteInvocationExecutor.java:39) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at org.springframework.remoting.support.RemoteInvocationBasedExporter.invoke(RemoteInvocationBasedExporter.java:78) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at org.springframework.remoting.support.RemoteInvocationBasedExporter.invokeAndCreateResult(RemoteInvocationBasedExporter.java:114) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at org.springframework.amqp.remoting.service.AmqpInvokerServiceExporter.onMessage(AmqpInvokerServiceExporter.java:80) ~[spring-amqp-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1457) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1348) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1324) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1303) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:785) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:769) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access0(SimpleMessageListenerContainer.java:77) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1010) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at java.lang.Thread.run(Thread.java:748) ~[?:1.8.0_161]
    at org.springframework.remoting.support.RemoteInvocationUtils.fillInClientStackTraceIfPossible(RemoteInvocationUtils.java:45) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at org.springframework.remoting.support.RemoteInvocationResult.recreate(RemoteInvocationResult.java:156) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at org.springframework.amqp.remoting.client.AmqpClientInterceptor.invoke(AmqpClientInterceptor.java:78) ~[spring-amqp-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at com.sun.proxy.$Proxy108.findJobById(Unknown Source) ~[?:?]

接口详情:

interface IJobQueryService{

    fun findJobById(args : QueryJobArgs) : QueryJobResponse

}

interface IJobService : IJobQueryService

服务实现细节:

class JobController(val jobQueryService: IJobQueryService) : IJobService{


    override fun findJobById(args: QueryJobArgs): QueryJobResponse {
        return jobQueryService.findJobById(args)
    }


}

BeanConfiguration:(注意:为简单起见未指定完整配置)

    @Bean
    fun rmsExporter(rabbitTemplate: RabbitTemplate):AmqpInvokerServiceExporter {
        val exporter = AmqpInvokerServiceExporter();
        exporter.amqpTemplate = rabbitTemplate;
        exporter.service = JobController(JobQueryProvider());
        exporter.serviceInterface = IJobService::class.java
        exporter.messageConverter = producerJackson2MessageConverter()
        return exporter;
    }

    @Bean
    fun rmxProxy(rabbitTemplate: RabbitTemplate) : AmqpProxyFactoryBean {
        val proxy = AmqpProxyFactoryBean();
        proxy.amqpTemplate = rabbitTemplate;
        proxy.serviceInterface = IJobService::class.java
        proxy.routingKey = "rms.webservice.api"
        return proxy;
    }

调用详细信息

val jobservice  = applicationContext.getBean(IJobService::class.java)

println("Remoting Is On => " +  jobservice.findJobById(QueryJobArgs().apply { job = Job().apply { id = 1 } } ))

您尝试通过网络传输 JSON 的问题。

因此,AmqpClientInterceptor 将您的 QueryJobArgs 包装到 RemoteInvocation object 中,并且已经将其序列化为 JSON,例如:

(Body:'{"methodName":"findJobById","parameterTypes":["com.example.rabbiitmqremoting.args.job.QueryJobArgs"],"arguments":[{"job":{"id":1,"createdBy":null}}],"attributes":null}' MessageProperties [headers={__TypeId__=org.springframework.remoting.support.RemoteInvocation}, contentType=application/json, contentEncoding=UTF-8, contentLength=167, deliveryMode=PERSISTENT, priority=0, deliveryTag=0])

关注__TypeId__=org.springframework.remoting.support.RemoteInvocationheader。这个用于消费者端将内容反序列化为 RemoteInvocation。但是由于 arguments 没有(自动)信息被反序列化为 QueryJobArgs,它们仍然是 LinkedHashMap。因此Caused by: java.lang.Throwable: argument type mismatch.

作为解决方法,我建议您返回到 SimpleMessageConverter,它将使用标准 Java 序列化机制。

更新

好的!你知道我也用 JSON 破解了这个。

所以,我这样做了:

@Autowired
lateinit var objectMapper: ObjectMapper

@PostConstruct
fun init() {
    this.objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY)
}

并将此 objectMapper 注入到 RabbitConfig 中显示的所有 Jackson 转换器中。现在它按预期工作:

Hellow From RMS
Remoting Is On => com.example.rabbiitmqremoting.response.QueryJobResponse@151bf776

我还删除了所有与messageHandlerMethodFactory相关的修改。看起来它没有参与 RPC。 但是你可能需要它来做一些其他的事情。不过故事不同...