How to properly configure @Component classes
I have a SqsQueueSender that I can send messages to AWS. I want to test this course. My idea is that it should be a @Component
injected into the class that needs it. Importantly, I want to configure SqsQueueSender's
endpoint to be different in test and production environments.
I’ve been moving around classes in a variety of different ways@Autowired and @Component, but there are definitely some fundamental misconceptions. Here is my latest config:
package com.foo.fulfillmentApi.dao;
import com.amazonaws.services.sqs.AmazonSQSAsyncClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate;
import org.springframework.messaging.support.MessageBuilder;
@Component
public class SqsQueueSender {
private static final Logger LOGGER = LoggerFactory.getLogger(SqsQueueSender.class);
private final QueueMessagingTemplate queueMessagingTemplate;
@Autowired
AmazonSQSAsyncClient amazonSQSAsyncClient;
This value is from /resources/application.properties
private @Value("${sqs.endpoint}") String endpoint;
public SqsQueueSender(AmazonSQSAsyncClient amazonSqsAsyncClient) {
amazonSqsAsyncClient.setEndpoint(endpoint);
this.queueMessagingTemplate = new QueueMessagingTemplate(amazonSqsAsyncClient);
}
public void send(String queueName, String message) {
this.queueMessagingTemplate.convertAndSend(queueName, MessageBuilder.withPayload(message).build());
}
}
Error information about the startup status
Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
‘com.amazonaws.services.sqs.AmazonSQSAsyncClient’ available: expected
at least 1 bean which qualifies as autowire candidate. Dependency
annotations: {}
To implement SqsQueueSender
, you must pass AmazonSQSAsyncClient
. How do I ensure that this component can access existing beans of that type?
Solution
You need to create a configuration class. In your case, it will look like this:
@Configuration
public class AWSConfig {
@Bean(name ="awsClient")
public AmazonSQSAsync amazonSQSClient() {
AmazonSQSAsyncClient awsSQSAsyncClient
= new AmazonSQSAsyncClient();
set up the client
return awsSQSAsyncClient;
}
If there is a problem with injecting, add the qualifier in qsQueueSender:
@Autowired
@Qualifier("awsClient")
AmazonSQSAsyncClient amazonSQSAsyncClient;
You can also do this using an XML configuration, but this is the preferable approach because you are using comments.