Using Spring Boot with Java and SQS with Localstack

Marcos
4 min readNov 13, 2022

--

What is LocalStack?

From its READ.me:

LocalStack 💻 is a cloud service emulator that runs in a single container on your laptop or in your CI environment. With LocalStack, you can run your AWS applications or Lambdas entirely on your local machine without connecting to a remote cloud provider! Whether you are testing complex CDK applications or Terraform configurations, or just beginning to learn about AWS services, LocalStack helps speed up and simplify your testing and development workflow.

The official documentation is here: https://docs.localstack.cloud/overview/

What is AWS SQS?

SQS means Simple Queue Service and is a fully managed message queuing service that enables you to decouple and scale microservices, distributed systems, and serverless applications.

The official documentation is here: https://aws.amazon.com/sqs/

Running Localstack with Docker

This is my docker-compose.yml file:

version: '3.8'

services:
localstack:
container_name: "${LOCALSTACK_DOCKER_NAME-localstack_main}"
image: localstack/localstack:0.14.2
network_mode: bridge
ports:
- "127.0.0.1:4566:4566" # LocalStack Gateway
- "127.0.0.1:53:53" #
- "127.0.0.1:53:53/udp" #
- "127.0.0.1:443:443" #
- "127.0.0.1:4510-4530:4510-4530" # ext services port range
- "127.0.0.1:4571:4571" #
environment:
- DEBUG=${DEBUG-}
- SERVICES=${SERVICES-}
- DATA_DIR=${DATA_DIR-}
- LAMBDA_EXECUTOR=local
- LOCALSTACK_API_KEY=${LOCALSTACK_API_KEY-}
- HOST_TMP_FOLDER=${TMPDIR:-/tmp/}localstack
- DOCKER_HOST=unix:///var/run/docker.sock
- DISABLE_CORS_CHECKS=1
volumes:
- "${TMPDIR:-/tmp}/localstack:/tmp/localstack"
- "/var/run/docker.sock:/var/run/docker.sock"
networks:
mysql-compose-network:
driver: bridge

Now, run this command:

docker-compose up -d

We will create a queue using sqs with this command:

aws --endpoint-url=http://127.0.0.1:4576 sqs create-queue --queue-name test-queue

The result is:

The command to list queues is:

aws --endpoint-url=http://127.0.0.1:4566 sqs list-queues

Building a producer Spring Boot application

For this I used https://start.spring.io/

The dependency I used was:

<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-sqs</artifactId>
<version>1.12.341</version>
</dependency>

This code build a client for SQS:

@Configuration
public class AWSConfig {

public AWSCredentials credentials() {
AWSCredentials credentials = new BasicAWSCredentials(
"accesskey",
"secretkey"
);
return credentials;
}

@Bean
public AmazonSQS amazonSQS() {
return AmazonSQSClientBuilder
.standard()
.withEndpointConfiguration(getEndpointConfiguration("http://localhost:4566"))
.withCredentials(new AWSStaticCredentialsProvider(credentials()))
.build();
}

private AwsClientBuilder.EndpointConfiguration getEndpointConfiguration(String url) {
return new AwsClientBuilder.EndpointConfiguration(url, Regions.US_EAST_1.getName());
}

}

After this I made a service class to make operations with sqs:

import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.model.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.UUID;

@Service
public class SqsService {
private static final Logger LOGGER = LoggerFactory.getLogger(SqsService.class);
private final AmazonSQS amazonSQS;

public SqsService(AmazonSQS amazonSQS) {
this.amazonSQS = amazonSQS;
}

public CreateQueueResult createQueue(final String queueName) {
//TODO: create with createObjectRequest params
//CreateQueueRequest createRequest = new CreateQueueRequest(queueName)
// .addAttributesEntry("DelaySeconds", "60")
// .addAttributesEntry("MessageRetentionPeriod", "86400");
return amazonSQS.createQueue(queueName);
}

public ListQueuesResult listQueues() {
return amazonSQS.listQueues();
}

public DeleteQueueResult removeQueue(final String queueName) {
return amazonSQS.deleteQueue(queueName);
}


public SendMessageResult publishMessage(final String queueUrl, final String message) {
final ObjectMapper objectMapper = new ObjectMapper();
SendMessageRequest sendMessageRequest = null;
try {
sendMessageRequest = new SendMessageRequest().withQueueUrl(queueUrl)
.withMessageBody(objectMapper.writeValueAsString(message))
.withMessageDeduplicationId(UUID.randomUUID().toString());
return amazonSQS.sendMessage(sendMessageRequest);
} catch (JsonProcessingException e) {
LOGGER.error("JsonProcessingException e : {}", e.getMessage());
} catch (Exception e) {
LOGGER.error("Exception e : {}", e.getMessage());
}
return null;
}

public List<Message> receiveMessages(final String queueUrl) {
ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest();
receiveMessageRequest.setQueueUrl(queueUrl);
receiveMessageRequest.setWaitTimeSeconds(5);
receiveMessageRequest.setMaxNumberOfMessages(5);
return amazonSQS.receiveMessage(receiveMessageRequest).getMessages();
}

}

In order to facilitate the tests I made a controller and used OpenAPI:

@RestController
@RequestMapping(value = "/sqs")
@RequiredArgsConstructor
public class SqsControllerTests {

private final SqsService sqsService;

@PostMapping(value = "/{queueName}")
public ResponseEntity<?> createQueue(@PathVariable final String queueName){
return ResponseEntity.ok(sqsService.createQueue(queueName));
}

@GetMapping()
public ResponseEntity<?> listQueues(){
return ResponseEntity.ok(sqsService.listQueues());
}

@PostMapping(value = "/messages")
public ResponseEntity<?> createMessage(@RequestBody final SqsMessageRequest sqsMessageRequest){
return ResponseEntity.ok(sqsService.publishMessage(sqsMessageRequest.getQueueUrl(), sqsMessageRequest.getMessage()));
}

@GetMapping(value = "/messages/{queueName}")
public ResponseEntity<?> receiveMessage(@PathVariable final String queueName){
return ResponseEntity.ok(sqsService.receiveMessages( "http://localhost:4566/000000000000/" + queueName));
}

@DeleteMapping()
public ResponseEntity<?> deleteMessage(@PathVariable final String queueName){
return ResponseEntity.ok(sqsService.removeQueue( "http://localhost:4566/000000000000/" + queueName));
}
}
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.11</version>
</dependency>

application.properties:

server.port=8088
springdoc.swagger-ui.path=/swagger-ui.html

Now, when the application starts a swagger will appear:

You can use these URLs to:

  • create a queue;
  • list queues;
  • remove queues;
  • send messages to a queue;
  • get messages from a queue;

Now it’s time to send messages to the queue. Use the swagger and create some messages:

And finally, get the messages from the queue. Again, we can use swagger to verify the messages:

That’s it for today.

The code is here: https://github.com/mmarcosab/sqs-example
In the next text, I will go deep into operations with AWS SQS.

--

--