Alice
Alice

Reputation: 95

Spring-integration gateway cannot be autowired, no qualifying bean found

I am trying to send the output from a spring batch process to RabbitMQ. To avoid hard dependency on Rabbitmq, I used spring-integration as suggested in Is there an API in spring-xd to write to a message bus?. I had everything working fine with messages being pushed to RabbitMQ, until I decided to autowire or instantiate the beans via Spring.

<context:component-scan base-package="com.test.*"/> 
<channel id="input" />

<rabbit:connection-factory id="connectionFactory" />

<rabbit:template id="amqpTemplate" connection-factory="connectionFactory"
    exchange="testExchange" routing-key="foo.bar" />
<rabbit:admin connection-factory="connectionFactory" />
<rabbit:queue name="testQueue" id="timeseriesQueue" />
<rabbit:topic-exchange name="testExchange"
    id="testExchange">
    <rabbit:bindings>
        <rabbit:binding queue="testQueue" pattern="foo.*" />
    </rabbit:bindings>
</rabbit:topic-exchange>

<!-- Send message to rabbitmq -->
<gateway id="testGateway"
    service-interface="com.test.TestService"
    default-request-channel="input" />


<amqp:outbound-channel-adapter channel="input"
    amqp-template="amqpTemplate" exchange-name="testExchange"
    routing-key="foo.bar" />

The testService is just an interface with the method sendMessage.

The spring batch job has an itemWriter, which uses the gateway bean to write to RabbitMQ

In the write method of itemWriter, when I instantiated the bean using ApplicationContext, like below, it worked well

AbstractApplicationContext ctx =
                new ClassPathXmlApplicationContext("META-INF/spring/integration/rabbit.xml");

     TestService service = ctx.getBean("testGateway", TestService.class);
    service.sendMessage(items);
    ctx.close();

However, when I tried to autowire it, like below:

@Autowired
TestService service;

I get the following exception:

Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.test.TestService com.test.TransportItemWriter.testGateway; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.test.TestService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:508)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289)
... 22 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.test.TestService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1103)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:963)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480)
... 24 more

I tried looking around, but most examples (in spring-integration samples) of Gateway invoke it via ApplicationContext. I found http://java.dzone.com/articles/spring-integration-gateways-1, and added whatever annotation I thought I was missing, but could not get it working.

Any pointers are greatly appreciated.

Upvotes: 4

Views: 8567

Answers (3)

javalderas
javalderas

Reputation: 73

It's a old question I know, but I had a Similar Issue:

I would use a anotated class @MessagingGateway interface called MySFTPUploadGateway.java (is a gateway of course) placed in mydependency1.jar. Also I have a SpringBoot app called ApplicationMain.jar, but when i start my application this crash because ApplicationMain.jar, on runtime, not found MySFTPUploadGateway.class for autowiring as a Bean. I tried @ComponentScan("<path_to_MySFTPUploadGateway.class_on_mydependency1>"), also with @EnableIntegration but anything worked.

Reading a little about this, I Found https://github.com/spring-projects/spring-boot/issues/2037, cool, I think I have my solution with @IntegrationComponentScan ( the clue that gave me @jogo). But... This anotation only works with @EnableAutoConfiguration. This is the key.

So put your:

@EnableAutoConfiguration
@IntegrationComponentScan("<yourpathPackage>")

..and keep it running !

Upvotes: 5

jogo
jogo

Reputation: 111

I was dealing with similar issue recently. The solution was to add new annotation in config:

@IntegrationComponentScan("path.to.your.gateway")

Upvotes: 8

Gary Russell
Gary Russell

Reputation: 174584

Autowiring is functionally equivalent to getting the bean from the context (unless there's more than one instance, in which case, you need the right variable name, or a @Qualifier), but that would give you a different error. Is the gateway in the same context as the ItemWriter?

`META-INF/spring/integration/rabbit.xml`

implies it's in its own context. Are you <import/> ing in into your job context?

I usually debug issues like this by turning on debug logging for org.springframework; it emits copious logs for bean wiring.

Another good debug technique is to @Autowire the ApplicationContext and print out ctx.getBeanFactory().toString().

Upvotes: 2

Related Questions