我试图了解基于骆驼的 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
我有几个问题:
在客户端,我在 UpdateDeliveryDetailsFromClient.java 类中自动连接 DeliveryService 接口,但由于 bean 位于
<camel:proxy..
. 有没有办法使用@Autowired 注解在这里注入bean?当调用方法具有不同的方法签名时,为什么 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(文件: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), 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