Spring Boot Listener for AWS SQS With Spring Cloud
Spring Cloud AWS makes it easy to create a Java method that listens for messages on an Amazon SQS queue. Between Spring Boot and Spring Cloud, I was surprised by just how little code I needed to make all this happen.
The key is that when you have the right dependencies in your Maven POM, all you have to do is annotate your listener method with @SqsListener
:
@SqsListener("your-queue-name")
public void listen(DataObject message) {
LOG.info("!!!! received message {} {}", message.getFoo(), message.getBar());
}
The dependency on spring-cloud-starter-aws
takes care of initializing everything and scanning for annotated methods.
I put a gist on Github to illustrate the full Java class and full Maven POM.
Converting Messages to Java Objects
Your listener method can accept a String as an argument, or it can convert JSON in the message into Java objects. Spring will use Jackson to convert the incoming JSON to Java, with appropriate annotations:
@JsonCreator
public DataObject(@JsonProperty("foo") String foo, @JsonProperty("bar") String bar) {
this.foo = foo;
this.bar = bar;
}
Command Line Arguments and Authentication
You specify AWS credentials and region through Spring Boot properties. I passed these as command line arguments through Eclipse, where I was debugging locally/not on AWS:
--cloud.aws.region.static=us-east-1
set my region to US East 1 (Northern VA).--cloud.aws.credentials.useDefaultAwsCredentialsChain=true
tells Spring Boot to use the AWSDefaultAWSCredentialsChain
, which will pull credentials from either environment vars or~/.aws/credentials
file.I also set the environment variable
AWS_PROFILE
for the default credentials chain to find my credentials under the correct profile.
If I were running in AWS itself, the EC2 instance metadata could have determined the region automatically, and also provided credentials via the instance profile.
Testing via AWS Console
I used the AWS console to send test messages. The main catch is that if you are using JSON messages and using Spring to automatically deserialize JSON to your objects via @JsonProperty
annotations, you will need to specify the message attribute (header) contentType
with value application/json
. Otherwise, the conversion will fail with an unhelpful error message like "Cannot convert from [java.lang.String] to .... for GenericMessage ...." with no indication why there was a failure.
There is another alternative for reconfiguring the default Spring messaging classes to ignore the contentType
header.