Java – How to properly configure @Component classes

How to properly configure @Component classes… here is a solution to the problem.

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.

Related Problems and Solutions