使用 JMS 进行 Camel Spring 远程处理 - 不明确的方法调用 服务器项目代码客户端代码

问题描述

我试图了解基于 Camel 的 bean 和 spring 远程处理。

我创建了两个项目:

  • 一个充当带有嵌入式 ActiveMQ 的服务器
  • 一个使用骆驼弹簧远程代理作为客户端使用接口。

服务器端接口是 DeliveryService,它由 DeliveryServiceImpl 类实现,该类有两个方法重载,方法签名不同。列出以下代码后,独立服务器运行没有任何问题。

     String updateDelivery(String address);
     String updateDelivery(String address,String zipCode);

在客户端,包含接口,并注入到实际调用方法的 bean 中。下面是那个的xml配置。

    <camel:proxy id="deliveryService" serviceInterface="com.remote.client.DeliveryService" serviceUrl="direct:input"/>
    
    <bean id="deliveryInfo" class="com.remote.client.UpdateDeliveryDetailsFromClient">
       <property name="deliveryService" ref="deliveryService" />
    </bean>

现在,当我执行客户端时,我看到服务器端被调用但收到 Ambiguous method invocation 异常。

org.apache.camel.component.bean.AmbiguousMethodCallException: Ambiguous method invocations possible: [public java.lang.String com.springremote.srvr.DeliveryServiceImpl.updateDelivery(java.lang.String),public java.lang.String com.springremote.srvr.DeliveryServiceImpl.updateDelivery(java.lang.String,java.lang.String)] on the exchange: Exchange[ID-thirumurthi-HP-1615077478318-0-1]
  • 根据文档,我希望 Camel BeanProcesser 应该能够调用正确的方法

通过一点点挖掘,我注意到当使用多个参数调用接口时客户端无法转换。下面是客户端日志

TIME STARTED : ======> 2021-03-06T22:14:12.142636200
22:14| INFO | CamelLogger.java 158 | client side log :ID-thirumurthi-HP-1615097652037-0-2 ==  Renton
... the result updating address : Renton
22:14| INFO | CamelLogger.java 158 | client side log :ID-thirumurthi-HP-1615097652037-0-4 ==  [Ljava.lang.Object;@6f70a21b
... the result updating address zip both : [Ljava.lang.Object;@6f70a21b

我有几个问题:

  1. 在客户端,我在类 UpdateDeliveryDetailsFromClient.java 中自动连接了 DeliveryService 接口,但由于 bean 在 <camel:proxy.. 内,spring 无法解析它。有什么办法可以使用@Autowired注解在这里注入bean吗?

  2. 调用方法有不同的方法签名时,为什么Camel在这里无法识别正确的bean方法? (我可以尝试其他选项,例如在 Camel 标头中指定方法名称或直接调用方法。)

注意:当我在界面中尝试使用一种方法时,流程有效。

详细的日志异常在底部

服务器项目代码

package com.springremote.srvr;
public interface DeliveryService {
    
     String updateDelivery(String address);
     String updateDelivery(String address,String zipCode);
}
package com.springremote.srvr;
import org.apache.camel.Handler;
public class DeliveryServiceImpl implements DeliveryService{
    
    @Override
    public String updateDelivery(String address) {
        return "<< SERVER >> : Delivery Info updated with address ONLY : "+address;
    }

    @Override
    public String updateDelivery(String address,String zipCode) {
        return "<< SERVER>> :Delivery Info updated with address & zip :"+address +" & " + zipCode;
    }  
}
  • Spring DSL 上下文 xml (file:context-springremote-server.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:broker="http://activemq.apache.org/schema/core"
    xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core.xsd">

    <import resource="activemq-broker.xml" />
    <bean id="deliveryService" class="com.springremote.srvr.DeliveryServiceImpl" />

  <!--  Don't use org.apache.activemq.camel.component.ActiveMQComponent since this is part of older activemq-camel dependency and doesn't working with camel 3.0+ -->
    <bean id="activemq" class="org.apache.camel.component.activemq.ActiveMQComponent">
        <property name="brokerURL" value="tcp://localhost:61616" />
    </bean>
    <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
        <route>
            <from uri="activemq:queue:example" />
            <log message="serverside log => ${header.camelFileName} = ${body}" />
            <to uri="bean:deliveryService" /> 
        </route>
    </camelContext>
</beans>

activemq-borker.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:broker="http://activemq.apache.org/schema/core"
       xsi:schemaLocation="
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
         http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">

    <!-- setup a real ActiveMQ broker which listen on port 61616 -->
    <broker:broker useJmx="false" persistent="false" brokerName="mybroker">
        <broker:transportConnectors>
            <broker:transportConnector name="tcp" uri="tcp://localhost:61616"/>
        </broker:transportConnectors>
    </broker:broker>
</beans>
  • 我在类路径中有一个 log4j.properties 文件
  • 我使用 Main() 方法使用以下代码执行了此服务器。这按预期运行。
package com.springremote.srvr;
import org.apache.camel.main.Main;
import org.apache.camel.spring.SpringCamelContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClasspathXmlApplicationContext;
public class DeliveryServiceServerUsingCamel3Main {

    public static void main(String[] args) {
        Main mainapp= new Main();
        ApplicationContext context = new ClasspathXmlApplicationContext(
                "context-springremote-server.xml");
        SpringCamelContext camelContext = (SpringCamelContext)context.getBean("camel");
        mainapp.addConfiguration(camelContext);     
        try {
            mainapp.run();
        } catch (Exception e) {
            e.printstacktrace();
        }       
    }
}

客户端代码

package com.remote.client;
public interface DeliveryService {
     String updateDelivery(String address);
     String updateDelivery(String address,String zipCode);
}
package com.remote.client;
import org.springframework.beans.factory.annotation.Autowired;
public class UpdateDeliveryDetailsFromClient {
    // Didn't include the getter setter method here.
    DeliveryService deliveryService;
    
    public String updateDelivery(String updateInfo) {
        return this.getDeliveryService().updateDelivery(updateInfo);
    }

    public String updateDelivery(String address,String zipCode) {
        return this.getDeliveryService().updateDelivery(address,zipCode);
    }
}
  • 上下文文件名 delivery-service-client-remote-context.xml
<!-- <beans tag not included,it is mostly the same as in the server side context.xml-->    
    <bean id="activemq" class="org.apache.camel.component.activemq.ActiveMQComponent">
        <property name="brokerURL" value="tcp://localhost:61616"/>
    </bean>
    <camel:proxy id="deliveryService" serviceInterface="com.remote.client.DeliveryService" serviceUrl="direct:input"/>
    
    <bean id="deliveryInfo" class="com.remote.client.UpdateDeliveryDetailsFromClient">
       <property name="deliveryService" ref="deliveryService" />
    </bean>
    
    <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
        <route>
            <from uri="direct:input" />
            <log message="client side log : ${body}"/>
            <to uri="activemq:queue:example" />
        </route>
    </camelContext>
</beans>
package com.remote.client;
import java.time.LocalDateTime;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.impl.engine.DefaultProducerTemplate;
import org.apache.camel.spring.SpringCamelContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClasspathXmlApplicationContext;

public class DeliveryServiceClientMainSeperateVM {

    public static void main(String[] args) throws Exception{

       ApplicationContext appContext = new ClasspathXmlApplicationContext("delivery-service-client-remote-context.xml");
        SpringCamelContext camelContext = (SpringCamelContext)appContext.getBean("camel");
        try {
            System.out.println("STARTED @ : ======> "+LocalDateTime.Now());
            camelContext.start();          
            

            UpdateDeliveryDetailsFromClient shipmentReceiver = camelContext.getRegistry().lookupByNameAndType("deliveryInfo",UpdateDeliveryDetailsFromClient.class);
            String updateStatus = shipmentReceiver.updateDelivery("Renton");
            System.out.println("... the result updating address : " + updateStatus);
            updateStatus = shipmentReceiver.updateDelivery("Renton","98055");
            System.out.println("... the result updating address zip both : " + updateStatus);
            Thread.sleep(15000);
            System.out.println("STOPPED @ : ========> "+LocalDateTime.Now());
        } finally {
            camelContext.stop();
        }    
    }
}
日志详情:
org.apache.camel.component.bean.AmbiguousMethodCallException: Ambiguous method invocations possible: [public java.lang.String com.springremote.srvr.DeliveryServiceImpl.updateDelivery(java.lang.String),java.lang.String)] on the exchange: Exchange[ID-thirumurthi-HP-1615077478318-0-1]
    at org.apache.camel.component.bean.BeanInfo.chooseBestPossibleMethodInfo(BeanInfo.java:871)
    at org.apache.camel.component.bean.BeanInfo.chooseMethodWithMatchingBody(BeanInfo.java:800)
    at org.apache.camel.component.bean.BeanInfo.chooseMethod(BeanInfo.java:634)
    at org.apache.camel.component.bean.BeanInfo.createInvocation(BeanInfo.java:286)
    at org.apache.camel.component.bean.BeanInfo.createInvocation(BeanInfo.java:186)
    at org.apache.camel.component.bean.AbstractBeanProcessor.process(AbstractBeanProcessor.java:129)
    at org.apache.camel.component.bean.BeanProcessor.process(BeanProcessor.java:55)
    at org.apache.camel.component.bean.BeanProducer.process(BeanProducer.java:41)
    at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:134)
    at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$RedeliveryState.run(RedeliveryErrorHandler.java:476)
    at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:185)
    at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:59)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:87)
    at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:228)
    at org.apache.camel.impl.engine.DefaultAsyncProcessorAwaitManager.process(DefaultAsyncProcessorAwaitManager.java:78)
    at org.apache.camel.support.AsyncProcessorSupport.process(AsyncProcessorSupport.java:40)
    at org.apache.camel.component.jms.EndpointMessageListener.onMessage(EndpointMessageListener.java:129)
    at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:736)
    at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:696)
    at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:674)
    at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:318)
    at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:257)
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncmessageListenerInvoker.invokeListener

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)