Previously, we had an application that reads a property from a distributed configuration. This post shows how to use Micronaut with the Consul’s Service Discovery. We will use two applications where one of them accesses the other’s URI. Also, we will use similar requisites and run everything in a local environment.
Consul Service Registration And Discovery
Service Discovery means that a service is discoverable. In our case, it is discoverable in Consul. Therefore, an application has to register itself in Consul, so others become aware of it. The registration typically happens during application startup. Note that an instance of Consul needs to be running before we proceed. For simplicity, our sample applications perform service registration with Consul at startup.
Create Two Micronaut Applications For Consul Service Discovery
We will play around with two Micronaut applications. The first one, app1, runs on port 8081, registers itself in Consul, and returns some application information. The other application, app2, runs on port 8080 and accesses the latter’s URI from the controller class. Therefore, app2 access a URI in app1 to retrieve a JSON string.
Create these applications with the Consul Discovery feature, as shown below.
The First Micronaut Application
The first Micronaut has the following controller class. It exposes a URI ( /appinfo) that returns JSON string data. We won’t access this URI directly on the browser.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | package com.turreta.micronaut.consul.servicediscovery.app1; import io.micronaut.http.MediaType; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; @Controller("/appinfo") public class AppInfoController { String appInfo = "{name: 'app1', version: 1}"; /** * Retrieve App Info * * @return JSON String */ @Get(produces = MediaType.APPLICATION_JSON) public String index() { return appInfo; } } |
Its application.yml has the following codes.
1 2 3 4 5 6 7 8 9 10 | micronaut: server: port: 8081 application: name: servicediscoveryApp1 consul: client: registration: enabled: true defaultZone: ${CONSUL_HOST:localhost}:${CONSUL_PORT:8500} |
Finally, its pom.xml has the following content.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.turreta.micronaut.consul.servicediscovery.app1</groupId> <artifactId>servicediscovery-app1</artifactId> <version>0.1</version> <packaging>${packaging}</packaging> <parent> <groupId>io.micronaut</groupId> <artifactId>micronaut-parent</artifactId> <version>2.4.1</version> </parent> <properties> <packaging>jar</packaging> <jdk.version>14</jdk.version> <release.version>14</release.version> <micronaut.version>2.4.1</micronaut.version> <exec.mainClass>com.turreta.micronaut.consul.servicediscovery.app1.Application</exec.mainClass> <micronaut.runtime>netty</micronaut.runtime> </properties> <repositories> <repository> <id>central</id> <url>https://repo.maven.apache.org/maven2</url> </repository> </repositories> <dependencies> <dependency> <groupId>io.micronaut</groupId> <artifactId>micronaut-inject</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>io.micronaut</groupId> <artifactId>micronaut-validation</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>io.micronaut</groupId> <artifactId>micronaut-http-server-netty</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>io.micronaut.discovery</groupId> <artifactId>micronaut-discovery-client</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.micronaut.test</groupId> <artifactId>micronaut-test-junit5</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.micronaut</groupId> <artifactId>micronaut-http-client</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>io.micronaut</groupId> <artifactId>micronaut-runtime</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <scope>compile</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>io.micronaut.build</groupId> <artifactId>micronaut-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <!-- Uncomment to enable incremental compilation --> <!-- <useIncrementalCompilation>false</useIncrementalCompilation> --> <annotationProcessorPaths combine.children="append"> </annotationProcessorPaths> <compilerArgs> <arg>-Amicronaut.processing.group=com.turreta.micronaut.consul.servicediscovery.app1</arg> <arg>-Amicronaut.processing.module=servicediscovery-app1</arg> </compilerArgs> </configuration> </plugin> </plugins> </build> </project> |
Note the service name for registration with Consul. When we start up this application, it will register itself as servicediscovery-app1.
The Second Micronaut Application That Access URL in servicediscovery-app1
The second Micronaut application will access the URL in servicediscovery-app1 from the following class without directly relying on its IP address and port number.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | package com.turreta.micronaut.consul.servicediscovery.app2; import io.micronaut.http.MediaType; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; import javax.inject.Inject; @Controller("/another-app-info") public class AnotherAppInfoController { @Inject AppInfoClientService appInfoClientService; @Get(produces = MediaType.TEXT_PLAIN) public String index() { return " The other app's info : " + appInfoClientService.getAppInfo(); } } |
Its application.yml has the following lines.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.turreta.micronaut.consul.servicediscovery.app2</groupId> <artifactId>servicediscovery-app2</artifactId> <version>0.1</version> <packaging>${packaging}</packaging> <parent> <groupId>io.micronaut</groupId> <artifactId>micronaut-parent</artifactId> <version>2.4.1</version> </parent> <properties> <packaging>jar</packaging> <jdk.version>14</jdk.version> <release.version>14</release.version> <micronaut.version>2.4.1</micronaut.version> <exec.mainClass>com.turreta.micronaut.consul.servicediscovery.app2.Application</exec.mainClass> <micronaut.runtime>netty</micronaut.runtime> </properties> <repositories> <repository> <id>central</id> <url>https://repo.maven.apache.org/maven2</url> </repository> </repositories> <dependencies> <dependency> <groupId>io.micronaut</groupId> <artifactId>micronaut-inject</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>io.micronaut</groupId> <artifactId>micronaut-validation</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>io.micronaut</groupId> <artifactId>micronaut-http-server-netty</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>io.micronaut.discovery</groupId> <artifactId>micronaut-discovery-client</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.micronaut.test</groupId> <artifactId>micronaut-test-junit5</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.micronaut</groupId> <artifactId>micronaut-http-client</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>io.micronaut</groupId> <artifactId>micronaut-runtime</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <scope>compile</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>io.micronaut.build</groupId> <artifactId>micronaut-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <!-- Uncomment to enable incremental compilation --> <!-- <useIncrementalCompilation>false</useIncrementalCompilation> --> <annotationProcessorPaths combine.children="append"> </annotationProcessorPaths> <compilerArgs> <arg>-Amicronaut.processing.group=com.turreta.micronaut.consul.servicediscovery.app2</arg> <arg>-Amicronaut.processing.module=servicediscovery-app2</arg> </compilerArgs> </configuration> </plugin> </plugins> </build> </project> |
The only information this application need is the other application’s registered name in Consul. In this case, it’s servicediscoveryApp1. Consider the following codes.
1 2 3 4 5 6 7 8 9 10 | package com.turreta.micronaut.consul.servicediscovery.app2; import io.micronaut.http.annotation.Get; import io.micronaut.http.client.annotation.Client; @Client(id="servicediscoveryApp1") public interface AppInfoClientService { @Get("/appinfo") String getAppInfo(); } |
We have an interface that is annotated with @Client with id referring to servicediscoveryApp1. Then, our codes inject an instance of that interface in our controller class.
The
Micronaut Applications And Consul Service Discovery In Action
Finally, let’s try out the Consul Service Discovery using our Micronaut applications. Start the applications up and access the Consul UI Dashboard.
Then, access the servicediscoveryApp2 URL.
As we can see, servicediscoveryApp2 displayed a page with information that came from servicediscovery1. For more information, check out the Consul Service Discovery documentation.