$ mn create-app my-nats-app --features nats
Micronaut Nats
Integration between Micronaut and nats.io
Version:
1 Introduction
This project includes integration between Micronaut and nats.io. The standard Java Client is used to do the actual publishing and consuming.
2 Release History
For this project, you can find a list of releases (with release notes) here:
3 Using the Micronaut CLI
To create a project with NATS support using the Micronaut CLI, supply the nats
feature to the features
flag.
This will create a project with the minimum necessary configuration for NATS.
Messaging Application
The Micronaut CLI can generate messaging applications. This will create a Micronaut app with NATS support, and without an HTTP server (although you can add one if you desire). The profile also provides a couple commands for generating NATS consumers and producers.
To create a NATS messaging application, use the the following command:
$ mn create-messaging-app my-nats-service --features nats
As you’d expect, you can start the application with ./gradlew run
(for Gradle) or ./mvnw compile exec:exec
(Maven). The application will (with the default config) attempt to connect to NATS at nats://localhost:4222
, and will continue to run without starting up an HTTP server. All communication to/from the service will take place via NATS producers and/or consumers.
Within the new project, you can now run the NATS specific code generation commands:
$ mn create-nats-producer Message | Rendered template Producer.java to destination src/main/java/my/nats/app/MessageProducer.java $ mn create-nats-listener Message | Rendered template Listener.java to destination src/main/java/my/nats/app/MessageListener.java
4 NATS Quick Start
To add support for NATS.io to an existing project, you should first add the Micronaut NATS configuration to your build configuration. For example:
implementation("io.micronaut.nats:micronaut-nats")
<dependency>
<groupId>io.micronaut.nats</groupId>
<artifactId>micronaut-nats</artifactId>
</dependency>
Creating a NATS Producer with @NatsClient
To create a NATS Producer
that sends messages you can simply define an interface that is annotated with @NatsClient.
For example the following is a trivial @NatsClient
interface:
import io.micronaut.nats.annotation.NatsClient;
import io.micronaut.nats.annotation.Subject;
import io.micronaut.messaging.annotation.Body;
@NatsClient (1)
public interface ProductClient {
@Subject("my-products") (2)
void send(String name);
void sendProduct(@Subject String brand, @Body String name); (3)
}
1 | The @NatsClient annotation is used to designate this interface as a client |
2 | The @Subject annotation indicates which subject the Message should be published to |
3 | It is also possible for the subject to be dynamic by making it a method argument |
At compile time Micronaut will produce an implementation of the above interface. You can retrieve an instance of ProductClient
either by looking up the bean from the ApplicationContext or by injecting the bean with @Inject
:
ProductClient client = applicationContext.getBean(ProductClient.class);
client.sendProduct("Nike", "Blue Trainers");
Creating a NATS Consumer with @NatsListener
To listen to NATS messages you can use the @NatsListener annotation to define a message listener.
The following example will listen for messages published by the ProductClient
in the previous section:
import io.micronaut.messaging.annotation.Body;
import io.micronaut.nats.annotation.NatsListener;
import io.micronaut.nats.annotation.Subject;
@NatsListener (1)
public class ProductListener {
@Subject("my-products") (2)
public void receive(@Body String name) { (3)
System.out.println("Got Product - " + name);
}
}
1 | The @NatsListener is used to designate this class as a listener. |
2 | The @Subject annotation is again used to indicate which subject to subscribe to. |
3 | The receive method defines one argument, which will receive the value. |
5 Configuring the connection
All properties on the Options are available to be modified, either through configuration or a BeanCreatedEventListener.
The properties that can be converted from the string values in a configuration file can be configured directly.
Property | Type | Description |
---|---|---|
|
java.util.List |
The list of addresses |
|
java.lang.String |
the username |
|
java.lang.String |
the password |
|
java.lang.String |
the token |
|
int |
times to try reconnect |
|
java.time.Duration |
time to wait |
|
java.time.Duration |
maximumTime for inital connection |
|
java.time.Duration |
time between server pings |
|
long |
size of the buffer, in bytes, used to store publish messages during reconnect |
|
java.lang.String |
custom prefix for request/reply inboxes |
|
boolean |
enable or disable echo messages, messages that are sent by this connection back to this connection |
|
boolean |
whether or not the client should support for UTF8 subject names |
|
java.lang.String |
path to the credentials file to use for authentication with an account enabled server |
Property | Type | Description |
---|---|---|
|
java.util.List |
The list of addresses |
|
java.lang.String |
the username |
|
java.lang.String |
the password |
|
java.lang.String |
the token |
|
int |
times to try reconnect |
|
java.time.Duration |
time to wait |
|
java.time.Duration |
maximumTime for inital connection |
|
java.time.Duration |
time between server pings |
|
long |
size of the buffer, in bytes, used to store publish messages during reconnect |
|
java.lang.String |
custom prefix for request/reply inboxes |
|
boolean |
enable or disable echo messages, messages that are sent by this connection back to this connection |
|
boolean |
whether or not the client should support for UTF8 subject names |
|
java.lang.String |
path to the credentials file to use for authentication with an account enabled server |
Without any configuration the defaults in the Options will be used. |
It is also possible to disable the integration entirely with nats.enabled: false
|
Connections
It is possible to configure multiple connections to the same server, different servers, or a single connection to one of a list of servers.
nats:
server1:
addresses:
- "nats://localhost:4222"
username: guest
password: guest
server2:
addresses:
- "nats://randomServer:4222"
username: guest
password: guest
NATS also supports a fail over connection strategy where the first server that connects successfully will be used among a list of servers. To use this option in Micronaut, simply supply a list of host:port
addresses.
nats:
addresses:
- "nats://localhost:4222"
- "nats://randomServer:4222"
username: guest
password: guest
When the configuration option nats.servers is used, no other options underneath nats are read; for example nats.username .
|
If you need to setup TLS, it can be configured this way:
nats:
addresses:
- "nats://localhost:4222" (1)
tls:
trust-store-path: /path/to/client.truststore.jks (2)
trust-store-password: secret
certificate-path: /path/to/certificate.crt (3)
1 | You can either use nats://localhost:4222 or tls://localhost:4222 as protocol. |
2 | You can configure a complete truststore |
3 | Or ou can use a single certificate for connecting to NATS securely. |
6 NATS Producers Using @NatsClient
The example in the quick start presented a trivial definition of an interface that be implemented automatically for you using the @NatsClient annotation.
The implementation that powers @NatsClient
(defined by the NatsIntroductionAdvice class) is, however, very flexible and offers a range of options for defining NATS clients.
6.1 Defining @NatsClient Methods
All methods that publish messages to NATS must meet the following conditions:
-
The method must reside in a interface annotated with @NatsClient.
-
The method or a method parameter must be annotated with @Subject.
-
The method must contain an argument representing the body of the message.
In order for all of the functionality to work as designed in this guide your classes must be compiled with the parameters flag set to true .
If your application was created with the Micronaut CLI, then that has already been configured for you.
|
Simple Producer
The easiest way for defining a producer is the following:
@Subject("my-products")
void sendProduct(String name);
Dynamic subject
void sendProduct(@Subject String topic, String name);
Publishing to Queues
The NATS server will route the message to the queue and select a message receiver. |
Return Type and RPC
If the producer defines a return type, it automatically will use the RPC logic and will wait for an answer from a consumer |
@Subject("product")
Product sendProduct(String name);
@Subject("product")
Single<Product> sendProduct(String name);
@Subject("product")
Maybe<Product> sendProduct(String name);
@Subject("product")
Flowable<Product> sendProduct(String name);
7 NATS Consumers Using @NatsListener
The quick start section presented a trivial example of what is possible with the @NatsListener annotation.
The implementation that powers @NatsListener
(defined by the NatsConsumerAdvice class) is, however, very flexible and offers a range of options for consuming NATS message.
7.1 Defining @NatsListener Methods
All methods that consume messages from NATS must meet the following conditions:
-
The method must reside in a class annotated with @NatsListener.
-
The method must be annotated with @Subject.
In order for all of the functionality to work as designed in this guide your classes must be compiled with the parameters flag set to true .
If your application was created with the Micronaut CLI, then that has already been configured for you.
|
Simple Consumer
The easiest way for defining a consumer is the following:
@Subject("my-products")
public void receive(String name) {
System.out.println("Got Product - " + name);
}
Queue Support
Subscribers may specify queue groups at subscription time. When a message is published to the group NATS will deliver it to a one-and-only-one subscriber.
Queue groups do not persist messages. If no listeners are available, the message is discarded. |
@Subject(value = "my-products", queue="my-queue")
public void receive(String name) {
System.out.println("Got Product - " + name);
}
Return Type and RPC
If the consumer defines a return type, it automatically will use the RPC logic and will send the return value to the producer |
@Subject(value = "my-products")
public Product receive(String name) {
return new Product(name);
}
8 NATS Health Indicator
This library comes with a health indicator for applications that are using the management
module in Micronaut. See the Health Endpoint documentation for more information about the endpoint itself.
The information reported from the health indicator is under the nats
key.
"nats": {
"status": "UP",
"details": {
"servers": ["nats://localhost:4222"]
}
}
To disable the NATS health indicator entirely, add endpoints.health.nats.enabled: false .
|
9 Repository
You can find the source code of this project in this repository: