Integrate AWS SQS with Java Using Spring Cloud AWS (Including FIFO & DLQ Support)

2 min read

Integrate AWS SQS with Java Using Spring Cloud AWS (Including FIFO & DLQ Support)

In this tutorial, you’ll learn how to build a Spring Boot application using Spring Cloud AWS to interact with Amazon SQS, including support for:

Sending messages
Consuming messages via listener
FIFO (First-In-First-Out) queues
DLQ (Dead Letter Queues)

We’ll also optionally use LocalStack to run AWS services locally.


Prerequisites

  • Java 17+
  • Maven 3.8+
  • Docker (for LocalStack)
  • AWS CLI (optional, used for setup)
  • Postman or curl (for testing)

Project Setup

Step 1: Create the Project

mvn archetype:generate -DgroupId=com.example.sqs -DartifactId=sqs-demo -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
cd sqs-demo

Step 2: Update pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>io.awspring.cloud</groupId>
        <artifactId>spring-cloud-aws-starter-sqs</artifactId>
        <version>3.0.2</version>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2022.0.4</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Step 3: Configure application.yml

spring:
  cloud:
    aws:
      region:
        static: us-east-1
      credentials:
        access-key: dummy
        secret-key: dummy
      sqs:
        endpoint: http://localhost:4566  # Point to LocalStack

Create Core Components

Main Application

package com.example.sqs;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.aws.messaging.config.annotation.EnableSqs;

@SpringBootApplication
@EnableSqs
public class SqsDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SqsDemoApplication.class, args);
    }
}

Message Controller

package com.example.sqs.controller;

import lombok.RequiredArgsConstructor;
import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequiredArgsConstructor
@RequestMapping("/messages")
public class MessageController {

    private final QueueMessagingTemplate messagingTemplate;

    @PostMapping
    public ResponseEntity<String> sendMessage(@RequestParam String body) {
        messagingTemplate.convertAndSend("test-queue", body);
        return ResponseEntity.ok("Message sent to SQS: " + body);
    }

    @PostMapping("/fifo")
    public ResponseEntity<String> sendFifoMessage(@RequestParam String body) {
        Map<String, Object> headers = new HashMap<>();
        headers.put("message-group-id", "group-1");
        messagingTemplate.convertAndSend("test-queue.fifo", body, headers);
        return ResponseEntity.ok("FIFO message sent: " + body);
    }

    @PostMapping("/fail")
    public ResponseEntity<String> sendFailingMessage(@RequestParam String body) {
        messagingTemplate.convertAndSend("test-queue-dlq-enabled", body);
        return ResponseEntity.ok("Failing message sent: " + body);
    }
}

SQS Listeners

package com.example.sqs.listener;

import org.springframework.cloud.aws.messaging.listener.annotation.SqsListener;
import org.springframework.stereotype.Component;

@Component
public class SqsMessageListener {

    @SqsListener("test-queue")
    public void handleStandard(String message) {
        System.out.println("Standard Queue: " + message);
    }

    @SqsListener("test-queue.fifo")
    public void handleFifo(String message) {
        System.out.println("FIFO Queue: " + message);
    }

    @SqsListener("test-queue-dlq-enabled")
    public void handleFailing(String message) {
        System.out.println("Failing Queue: " + message);
        if (message.contains("fail")) {
            throw new RuntimeException("Forcing failure for DLQ test");
        }
    }
}

Running with LocalStack

docker-compose.yml

version: "3.8"
services:
  localstack:
    image: localstack/localstack
    ports:
      - "4566:4566"
    environment:
      - SERVICES=sqs
      - DEFAULT_REGION=us-east-1
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
docker-compose up -d

Create Queues via AWS CLI

# Standard queue
aws --endpoint-url=http://localhost:4566 sqs create-queue --queue-name test-queue

# FIFO queue
aws --endpoint-url=http://localhost:4566 sqs create-queue \
  --queue-name test-queue.fifo \
  --attributes FifoQueue=true

# DLQ
aws --endpoint-url=http://localhost:4566 sqs create-queue --queue-name test-dlq

# DLQ ARN
DLQ_ARN=$(aws --endpoint-url=http://localhost:4566 sqs get-queue-attributes \
  --queue-url http://localhost:4566/000000000000/test-dlq \
  --attribute-name QueueArn --query 'Attributes.QueueArn' --output text)

# Main queue with DLQ
aws --endpoint-url=http://localhost:4566 sqs create-queue \
  --queue-name test-queue-dlq-enabled \
  --attributes "RedrivePolicy={\"deadLetterTargetArn\":\"$DLQ_ARN\",\"maxReceiveCount\":\"3\"}"

Test It Out

Start the app

mvn spring-boot:run

Send standard message

curl -X POST "http://localhost:8080/messages?body=hello"

Send FIFO message

curl -X POST "http://localhost:8080/messages/fifo?body=fifo-hello"

Send message to trigger DLQ

curl -X POST "http://localhost:8080/messages/fail?body=fail-test"

After 3 failures, check DLQ:

aws --endpoint-url=http://localhost:4566 sqs receive-message \
  --queue-url http://localhost:4566/000000000000/test-dlq

Summary

FeatureImplementedNotes
Send to SQS queueyesREST controller using QueueMessagingTemplate
Listen to SQS queueyesAnnotated with @SqsListener
FIFO queue supportyesUses .fifo suffix and message-group-id
DLQ supportyesRedrive policy forwards failed messages

🤞 Never miss a story from us, get weekly updates to your inbox!

Leave a Reply

Your email address will not be published. Required fields are marked *