apache-camel apache-cxf IllegalStateException: не удалось зарегистрировать объект под именем компонента 'cxf': объект уже привязан
Версия Camel: 2.12.2, CXF Версия: 2.7, Apache Tomcat: 7
У меня есть следующий camel-cxf.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:s0="http://www.huawei.com/bme/cbsinterface/cbs/businessmgr"
xmlns:s1="http://www.huawei.com/bme/cbsinterface/cbs/accountmgr"
xmlns:cxf="http://camel.apache.org/schema/cxf"
xmlns:http-conf="http://cxf.apache.org/transports/http/configuration"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd">
<bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor" />
<bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
<cxf:cxfEndpoint id="oneEndpoint"
address="${endpoint.address}"
serviceName="s1:WebService"
serviceClass="WebserviceClass"
endpointName="s1:WebSericePort_http"
wsdlURL="classpath:wsdl/WebService.wsdl">
<cxf:inInterceptors>
<ref bean="loggingInInterceptor" />
<ref bean="setSoapVersionInterceptor"/>
</cxf:inInterceptors>
<cxf:inFaultInterceptors>
<ref bean="loggingInInterceptor" />
<ref bean="setSoapVersionInterceptor"/>
</cxf:inFaultInterceptors>
<cxf:outInterceptors>
<ref bean="loggingOutInterceptor" />
</cxf:outInterceptors>
<cxf:outFaultInterceptors>
<ref bean="loggingOutInterceptor" />
</cxf:outFaultInterceptors>
</cxf:cxfEndpoint>
<http-conf:conduit name="*.http-conduit">
<http-conf:client
Connection="Keep-Alive"
ConnectionTimeout="60000"
ReceiveTimeout="90000"/>
</http-conf:conduit>
</beans>
В моем верблюжьем контексте у меня есть два процессора, которые используют конечную точку cxf для вызова двух разных операций. Чтобы сделать это, я использую производитель, который использует "cxf:bean:oneEndpoint" в качестве URI.
Проект представляет собой веб-приложение, развернутое в Tomcat 7.
Процессоры потребляют из двух разных очередей. После развертывания обе очереди передаются с сообщением. Проблема заключается в том, что один из процессоров сгенерирует исключение при вызове метода send в шаблоне производителя. Другой будет работать нормально. Исключение составляет:
org.apache.camel.ResolveEndpointFailedException: Failed to resolve endpoint:
cxf://bean:oneEndpoint due to: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'oneEndpoint': Initialization of bean failed;
nested exception is java.lang.IllegalStateException: Could not register object [org.apache.cxf.bus.spring.SpringBus@4b0af74c] under bean name 'cxf':
there is already object [org.apache.cxf.bus.spring.SpringBus@24c0fe59] bound
Полная трассировка стека может быть найдена здесь: http://pastebin.com/cDsQZ9r3
Во второй раз очереди получают сообщение одновременно, все отлично работает.
Есть идеи?
PS. Мой web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/META-INF/spring/*.xml</param-value>
</context-param>
</web-app>
Маршруты и процессоры:
<route id="route1" errorHandlerRef="eh1">
<from uri="{{queue1}}" />
<setHeader headerName="operationName">
<constant>Operation_1</constant>
</setHeader>
<process ref="FirstProcessor" />
<choice>
<when>
<simple>${in.headers.STATUS} == 'OK'</simple>
<inOnly uri="{{result_queue}}" />
</when>
<otherwise>
<inOnly uri="{{nok_result_queue}}" />
</otherwise>
</choice>
</route>
<route id="route2" errorHandlerRef="eh2">
<from uri="{{queue2}}" />
<setHeader headerName="operationName">
<constant>Operation_2</constant>
</setHeader>
<process ref="SecondProcessor" />
<choice>
<when>
<simple>${in.headers.STATUS} == 'OK'</simple>
<inOnly uri="{{result_queue}}" />
</when>
<otherwise>
<inOnly uri="{{nok_result_queue}}" />
</otherwise>
</choice>
</route>
<property name="producerTemplate" ref="firstProcessorTemplate" />
<property name="producerTemplateUri"
value="cxf:bean:oneEndpoint?headerFilterStrategy=#headerFilterStrategy" />
<property name="producerTemplate" ref="secondProcessorTemplate" />
<property name="producerTemplateUri"
value="cxf:bean:oneEndpoint?headerFilterStrategy=#headerFilterStrategy" />
2 ответа
Проблема в том, что обе очереди получают сообщение одновременно, поэтому обе они пытаются инициализировать SpringBus одновременно.
Проблема в том, что в BusWiringBeanFactoryPostProcessor это такой код:
if (!context.containsBean(name) && (create || Bus.DEFAULT_BUS_ID.equals(name))) {
SpringBus b = new SpringBus();
ConfigurableApplicationContext cctx = (ConfigurableApplicationContext)context;
cctx.getBeanFactory().registerSingleton(name, b);
b.setApplicationContext(context);
}
Таким образом, когда два компонента пытаются и инициализируют SpringBus в двух разных потоках, они могут одновременно ввести оператор if, что приведет к исключению.
Решение состоит в том, чтобы определить SpringBus в контексте приложения, чтобы ни один компонент не попытался создать новый SpringBus, поскольку он уже существует.
Пожалуйста, поделитесь определением маршрутов, которое использует сообщения из двух разных очередей. Также вы можете найти вариант использования многоадресной рассылки для параллельной обработки при получении сообщений из обеих очередей и продолжения дальнейшей работы.
<Путь>
<Просто>прямой:${header.operationName} простой>
RecipientList>
Путь>
Ваши маршруты (route1 и route) могут быть переименованы так же, как имя операции веб-службы. Наш код также похож на ваш. Мы не столкнулись с проблемой при таком подходе.