Joe Essey
Joe Essey

Reputation: 3527

How to configure @Component class appropriately

I have a SqsQueueSender to send messages to AWS. I want to test this class. My thought is that it should be a @Component that is injected in to the classes that need it. Importantly, I want to configure the endpoint of the SqsQueueSender to be different in testing vs. production environments.

I've been moving @Autowired and @Component around the classes various different ways but must have some basic misunderstanding. Here's my latest configuration:

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());
    }
}

The error message on startup states

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 an AmazonSQSAsyncClient. How do I make sure this component can access an existing bean of that type?

Upvotes: 3

Views: 6677

Answers (3)

Pravin Bansal
Pravin Bansal

Reputation: 4681

If you use springboot - define into your startup application file as below

@Bean
    public AmazonSNSAsync amazonSNSClient() {
        ClientConfiguration config = new ClientConfiguration();
        return AmazonSNSAsyncClient.asyncBuilder().withClientConfiguration(config)
                .withRegion(Regions.fromName(region))
                .withCredentials(new DefaultAWSCredentialsProviderChain())
                .build();

    }

Upvotes: 1

Maciej Kowalski
Maciej Kowalski

Reputation: 26522

You need to create a configuration class. In your case it would be something like this:

@Configuration
public class AWSConfig {

   @Bean(name ="awsClient")
   public AmazonSQSAsync amazonSQSClient() {
     AmazonSQSAsyncClient awsSQSAsyncClient 
            = new AmazonSQSAsyncClient();

     // set up the client

     return awsSQSAsyncClient;
}

If it has problems with injecting then add qualifier in qsQueueSender:

@Autowired
@Qualifier("awsClient")
AmazonSQSAsyncClient amazonSQSAsyncClient;

You can also do this using the xml configuration but as you are using annotations then this is more advisable approach.

Upvotes: 3

Monzurul Shimul
Monzurul Shimul

Reputation: 8396

Add @Component/@Service in com.amazonaws.services.sqs.AmazonSQSAsyncClient or return an object of that using @Bean annotation from configuration class.

Upvotes: 0

Related Questions