RESTful Web Service Discovery
1. Introduction
This is an in-depth article related to the discovery of Restful Web Service. Spring Boot framework has features to build applications. Spring Boot has features related to building rest services and unit testing the application. It has a eureka registry to lookup and discover the RESTful Web Services. The standard HATEOAS (Hypermedia As The Engine Of Application State) is used for discoverability of methods of the RESTful web services.
2. RESTful Web Service Discovery
2.1 Prerequisites
Java 8 or 9 is required on the Linux, windows, or Mac operating system. Maven 3.6.1 is required for building the spring and hibernate application.
2.2 Download
You can download Java 8 can be downloaded from the Oracle web site . Apache Maven 3.6.1 can be downloaded from Apache site. Spring framework’s latest releases are available from the spring website.
2.3 Setup
You can set the environment variables for JAVA_HOME and PATH. They can be set as shown below:
Setup for Java
JAVA_HOME="/desktop/jdk1.8.0_73" export JAVA_HOME PATH=$JAVA_HOME/bin:$PATH export PATH
The environment variables for maven are set as below:
Environment Setup for Maven
JAVA_HOME=”/jboss/jdk1.8.0_73″ export M2_HOME=/users/bhagvan.kommadi/Desktop/apache-maven-3.6.1 export M2=$M2_HOME/bin export PATH=$M2:$PATH
2.4 Building the application
2.4.1 Spring
You can start building Spring applications using the Spring Boot framework. Spring Boot has a minimal configuration of Spring. Spring Boot has features related to security, tracing, application health management, and runtime support for web servers. Spring configuration is done through maven pom.xml. The XML configuration is shown below:
Spring Configuration
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.springframework</groupId> <artifactId>spring-helloworld</artifactId> <version>0.1.0</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.4.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <properties> <java.version>1.8</java.version> </properties> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
You can create a HelloWorldController
class as the web controller. The class is annotated using @RestController
. Rest Controller is used to handle requests in Spring Model View Controller framework. Annotation @RequestMapping
is used to annotate the index()
method. The code for the HelloWorldController
class is shown below:
HelloWorld Controller
package helloworld; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RequestMapping; @RestController public class HelloWorldController { @RequestMapping("/") public String index() { return "Hello World\n"; } }
HelloWorldApp
is created as the Spring Boot web application. When the application starts, beans, and settings are wired up dynamically. They are applied to the application context. The code for HelloWorldApp
class is shown below:HelloWorld App
HelloWorldApp
package helloworld; import java.util.Arrays; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; @SpringBootApplication public class HelloWorldApp { public static void main(String[] args) { ApplicationContext ctx = SpringApplication.run(HelloWorldApp.class, args); System.out.println("Inspecting the beans"); String[] beans = ctx.getBeanDefinitionNames(); Arrays.sort(beans); for (String name : beans) { System.out.println("Bean Name" +name); } } }
Maven is used for building the application. The command below builds the application.
Maven Build Command
. mvn package
The output of the executed command is shown below.
The jar file spring-helloworld-0.1.0.jar is created. The following command is used for executing the jar file.
Run Command
. java -jar target/spring-helloworld-0.1.0.jar
The output of the executed command is shown below.
The curl command is invoked on the command line for the execution of the index method. The method returns a string “Hello World” text. @RestController aggregates the two annotations @Controller and @ResponseBody. This results in returning data. The output is shown below.
2.5 Rest Web Service -Discovery
Let us look at the service registry and discovery techniques of the RESTFul web services.
2.5.1 Service Registry
Netflix Eureka service registry is used for registering the services and for the client to look up the service. The registry helps in load balancing of the clients and decoupling of the consumers from the service providers. Spring initializr is used for getting the dependencies for an application and creating a setup for the developer.
Maven pom.xml is created to build the service application and for execution. The xml configuration is attached below:
Maven pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>rest-discovery-service</artifactId> <version>0.0.1-SNAPSHOT</version> <name>rest-discovery-service</name> <description>Spring Rest Service</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> </repository> </repositories> </project>
Eureka Service registry is enabled by using the @EnableEurekaServer
annotation in the service application. This registry annotation starts the Eureka Service registry.
Spring Boot Application
package org.javacodegeeks.discovery; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class ServiceRegistryAndDiscoveryApp { public static void main(String[] args) { SpringApplication.run(ServiceRegistryAndDiscoveryApp.class, args); } }
application.properties
is used for specifying the registry requirements. Application properties file is shown below:
application.properties
server.port=8761 eureka.client.register-with-eureka=false eureka.client.fetch-registry=false logging.level.com.netflix.eureka=OFF logging.level.com.netflix.discovery=OFF
Maven is used for building the application. The command below builds the application.
Maven Build Command
mvn package
The output of the executed command is shown below.
Build – Output
apples-MacBook-Air:complete bhagvan.kommadi$ mvn package [INFO] Scanning for projects... [INFO] ------------------------------------------------------------------------ [INFO] Reactor Build Order: [INFO] [INFO] rest-discovery-client [jar] [INFO] rest-discovery-service [jar] [INFO] rest-service-discovery [pom] [INFO] [INFO] -------< org.javacodegeeks:rest-discovery-client >-------- [INFO] Building rest-discovery-client 0.0.1-SNAPSHOT [1/3] [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ service-registration-and-discovery-client --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Copying 0 resource [INFO] Copying 1 resource [INFO] [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ service-registration-and-discovery-client --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 1 source file to /Users/bhagvan.kommadi/Desktop/JavacodeGeeks/Code/springrestdiscovery/complete/eureka-client/target/classes [INFO] [INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ rest-discovery-client --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] skip non existing resourceDirectory /Users/bhagvan.kommadi/Desktop/JavacodeGeeks/Code/springrestdiscovery/complete/eureka-client/src/test/resources [INFO] [INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ rest-discovery-client --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 1 source file to /Users/bhagvan.kommadi/Desktop/JavacodeGeeks/Code/springrestdiscovery/eureka-client/target/test-classes [INFO] [INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ rest-discovery-client --- [INFO] [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] Running org.javacodegeeks.client.ServiceRegistrationAndDiscoveryClientAppTests
Maven is used for executing the application. The command below runs the spring boot application related to the REST Service registry.
Maven Run Command
./mvnw spring-boot:run -pl eureka-service
The output of the executed command is shown below.
Execution – Output
apples-MacBook-Air:complete bhagvan.kommadi$ ./mvnw spring-boot:run -pl eureka-service [INFO] Scanning for projects... [INFO] [INFO] -------< org.javacodegeeks:rest-discovery-service >------- [INFO] Building rest-discovery-service 0.0.1-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] >>> spring-boot-maven-plugin:2.3.2.RELEASE:run (default-cli) > test-compile @ rest-discovery-service >>> [INFO] [INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ rest-discovery-service --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Copying 1 resource [INFO] Copying 0 resource [INFO] [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ rest-discovery-service --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ service-registration-and-discovery-service --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] skip non existing resourceDirectory /Users/bhagvan.kommadi/Desktop/JavacodeGeeks/Code/springrestdiscovery/eureka-service/src/test/resources [INFO] [INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ rest-discovery-service --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] <<< spring-boot-maven-plugin:2.3.2.RELEASE:run (default-cli) < test-compile @ rest-discovery-service <<< [INFO] [INFO] [INFO] --- spring-boot-maven-plugin:2.3.2.RELEASE:run (default-cli) @ rest--discovery-service --- [INFO] Attaching agents: [] . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.2.RELEASE) 2021-01-03 01:13:25.115 INFO 14770 --- [ main] o.j.d.ServiceRegistrationAndDiscoveryApp : No active profile set, falling back to default profiles: default 2021-01-03 01:13:26.593 INFO 14770 --- [ main] o.s.cloud.context.scope.GenericScope : BeanFactory id=4003ae63-5f2b-32e6-ac7b-ce9fc58862ab 2021-01-03 01:13:27.052 INFO 14770 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8761 (http) 2021-01-03 01:13:27.072 INFO 14770 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2021-01-03 01:13:27.073 INFO 14770 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.37] 2021-01-03 01:13:27.231 INFO 14770 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2021-01-03 01:13:27.232 INFO 14770 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2086 ms 2021-01-03 01:13:27.399 WARN 14770 --- [ main] c.n.c.sources.URLConfigurationSource : No URLs will be polled as dynamic configuration sources. 2021-01-03 01:13:27.399 INFO 14770 --- [ main] c.n.c.sources.URLConfigurationSource : To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath. 2021-01-03 01:13:27.421 INFO 14770 --- [ main] c.netflix.config.DynamicPropertyFactory : DynamicPropertyFactory is initialized with configuration sources: com.netflix.config.ConcurrentCompositeConfiguration@3971f0fe 2021-01-03 01:13:27.819 WARN 14770 --- [ main] o.s.boot.actuate.endpoint.EndpointId : Endpoint ID 'service-registry' contains invalid characters, please migrate to a valid format. 2021-01-03 01:13:28.020 INFO 14770 --- [ main] c.s.j.s.i.a.WebApplicationImpl : Initiating Jersey application, version 'Jersey: 1.19.1 03/11/2016 02:08 PM' 2021-01-03 01:13:29.178 WARN 14770 --- [ main] o.s.c.n.a.ArchaiusAutoConfiguration : No spring.application.name found, defaulting to 'application' 2021-01-03 01:13:29.179 WARN 14770 --- [ main] c.n.c.sources.URLConfigurationSource : No URLs will be polled as dynamic configuration sources. 2021-01-03 01:13:29.179 INFO 14770 --- [ main] c.n.c.sources.URLConfigurationSource : To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath. 2021-01-03 01:13:29.570 INFO 14770 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2021-01-03 01:13:30.786 INFO 14770 --- [ main] o.s.cloud.commons.util.InetUtils : Cannot determine local hostname 2021-01-03 01:13:32.222 INFO 14770 --- [ main] o.s.cloud.commons.util.InetUtils : Cannot determine local hostname 2021-01-03 01:13:33.226 INFO 14770 --- [ main] o.s.cloud.commons.util.InetUtils : Cannot determine local hostname 2021-01-03 01:13:33.260 WARN 14770 --- [ main] ockingLoadBalancerClientRibbonWarnLogger : You already have RibbonLoadBalancerClient on your classpath. It will be used by default. As Spring Cloud Ribbon is in maintenance mode. We recommend switching to BlockingLoadBalancerClient instead. In order to use it, set the value of `spring.cloud.loadbalancer.ribbon.enabled` to `false` or remove spring-cloud-starter-netflix-ribbon from your project. 2021-01-03 01:13:33.329 INFO 14770 --- [ main] o.s.c.n.eureka.InstanceInfoFactory : Setting initial instance status as: STARTING 2021-01-03 01:13:33.571 INFO 14770 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 2 endpoint(s) beneath base path '/actuator' 2021-01-03 01:13:33.605 INFO 14770 --- [ main] o.s.c.n.e.s.EurekaServiceRegistry : Registering application UNKNOWN with eureka with status UP 2021-01-03 01:13:33.609 INFO 14770 --- [ Thread-11] o.s.c.n.e.server.EurekaServerBootstrap : Setting the eureka configuration.. 2021-01-03 01:13:33.610 INFO 14770 --- [ Thread-11] o.s.c.n.e.server.EurekaServerBootstrap : Eureka data center value eureka.datacenter is not set, defaulting to default 2021-01-03 01:13:33.611 INFO 14770 --- [ Thread-11] o.s.c.n.e.server.EurekaServerBootstrap : Eureka environment value eureka.environment is not set, defaulting to test 2021-01-03 01:13:33.643 INFO 14770 --- [ Thread-11] o.s.c.n.e.server.EurekaServerBootstrap : isAws returned false 2021-01-03 01:13:33.644 INFO 14770 --- [ Thread-11] o.s.c.n.e.server.EurekaServerBootstrap : Initialized server context 2021-01-03 01:13:33.667 INFO 14770 --- [ Thread-11] e.s.EurekaServerInitializerConfiguration : Started Eureka Server 2021-01-03 01:13:33.679 INFO 14770 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8761 (http) with context path '' 2021-01-03 01:13:33.681 INFO 14770 --- [ main] .s.c.n.e.s.EurekaAutoServiceRegistration : Updating port to 8761 2021-01-03 01:13:34.688 INFO 14770 --- [ main] o.s.cloud.commons.util.InetUtils : Cannot determine local hostname 2021-01-03 01:13:34.711 INFO 14770 --- [ main] o.j.d.ServiceRegistrationAndDiscoveryApp : Started ServiceRegistrationAndDiscoveryApp in 13.08 seconds (JVM running for 13.895) 2021-01-03 01:13:44.938 INFO 14770 --- [nio-8761-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2021-01-03 01:13:44.939 INFO 14770 --- [nio-8761-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2021-01-03 01:13:44.957 INFO 14770 --- [nio-8761-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 18 ms ^C2021-01-03 01:15:40.159 INFO 14770 --- [extShutdownHook] o.s.c.n.e.s.EurekaServiceRegistry : Unregistering application UNKNOWN with eureka with status DOWN 2021-01-03 01:15:40.268 INFO 14770 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor' [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 02:23 min [INFO] Finished at: 2021-01-03T01:15:40+05:30 [INFO] ------------------------------------------------------------------------ apples-MacBook-Air:complete bhagvan.kommadi$
The second application (the client application) needs the Eureka Server and Eureka Discovery Client dependencies.
Maven pom.xml is created to build the application and for execution. The xml configuration is attached below:
Maven pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.2.RELEASE</version> <relativePath/> < > </parent> <groupId>org.javacodegeeks</groupId> <artifactId>rest-discovery-client</artifactId> <version>0.0.1-SNAPSHOT</version> <name>rest-discovery-client</name> <description>Spring Rest Client </description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> </repository> </repositories> </project>
Now client code needs to be developed. The service client will have @EnableDiscoveryClient
annotation for Netflix Eureka Discovery client implementation. Service client code is shown below:
Service Client Application
package org.javacodegeeks.client; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @EnableDiscoveryClient @SpringBootApplication public class ServiceRegistrationAndDiscoveryClientApp { public static void main(String[] args) { SpringApplication.run(ServiceRegistrationAndDiscoveryClientApp.class, args); } } @RestController class ServiceInstanceController { @Autowired private DiscoveryClient discoveryClient; @RequestMapping("/service-instances/{applicationName}") public List serviceInstancesByApplicationName( @PathVariable String applicationName) { return this.discoveryClient.getInstances(applicationName); } }
eureka-client registered is specified in the bootstrap.properties
. bootstrap.properties
is shown below:
bootstrap.properties
spring.application.name=rest-service-client
Below is the command to execute the Service client application.
bootstrap.properties
./mvnw spring-boot:run -pl eureka-client
The output of the executed command is shown below.
Build – Output
apples-MacBook-Air:complete bhagvan.kommadi$ ./mvnw spring-boot:run -pl eureka-client [INFO] Scanning for projects... [INFO] [INFO] -------< org.javacodegeeks:rest-discovery-client >-------- [INFO] Building rest-discovery-client 0.0.1-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] >>> spring-boot-maven-plugin:2.3.2.RELEASE:run (default-cli) > test-compile @ rest-discovery-client >>> [INFO] [INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ rest-discovery-client --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Copying 0 resource [INFO] Copying 1 resource [INFO] [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ rest-discovery-client --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 1 source file to /Users/bhagvan.kommadi/Desktop/JavacodeGeeks/Code/springrestdiscovery/complete/eureka-client/target/classes [INFO] [INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ rest-discovery-client --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] skip non existing resourceDirectory /Users/bhagvan.kommadi/Desktop/JavacodeGeeks/Code/springrestdiscovery/eureka-client/src/test/resources [INFO] [INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ rest-discovery-client --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 1 source file to /Users/bhagvan.kommadi/Desktop/JavacodeGeeks/Code/springrestdiscovery/eureka-client/target/test-classes [INFO] [INFO] <<< spring-boot-maven-plugin:2.3.2.RELEASE:run (default-cli) < test-compile @ rest-discovery-client <<< [INFO] [INFO] [INFO] --- spring-boot-maven-plugin:2.3.2.RELEASE:run (default-cli) @ rest-discovery-client --- [INFO] Attaching agents: [] . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.2.RELEASE) 2021-01-03 01:13:58.121 INFO 14841 --- [ main] ServiceRegistrationAndDiscoveryClientApp : No active profile set, falling back to default profiles: default 2021-01-03 01:13:59.204 INFO 14841 --- [ main] o.s.cloud.context.scope.GenericScope : BeanFactory id=cfe10556-feff-30ac-80c4-d8cc75409c7f 2021-01-03 01:13:59.530 INFO 14841 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2021-01-03 01:13:59.540 INFO 14841 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2021-01-03 01:13:59.540 INFO 14841 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.37] 2021-01-03 01:13:59.662 INFO 14841 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2021-01-03 01:13:59.662 INFO 14841 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1521 ms 2021-01-03 01:13:59.798 WARN 14841 --- [ main] c.n.c.sources.URLConfigurationSource : No URLs will be polled as dynamic configuration sources. 2021-01-03 01:13:59.798 INFO 14841 --- [ main] c.n.c.sources.URLConfigurationSource : To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath. 2021-01-03 01:13:59.808 INFO 14841 --- [ main] c.netflix.config.DynamicPropertyFactory : DynamicPropertyFactory is initialized with configuration sources: com.netflix.config.ConcurrentCompositeConfiguration@2fc2a205 2021-01-03 01:13:59.866 WARN 14841 --- [ main] o.s.boot.actuate.endpoint.EndpointId : Endpoint ID 'service-registry' contains invalid characters, please migrate to a valid format. 2021-01-03 01:14:00.979 INFO 14841 --- [ main] o.s.cloud.commons.util.InetUtils : Cannot determine local hostname 2021-01-03 01:14:01.049 WARN 14841 --- [ main] c.n.c.sources.URLConfigurationSource : No URLs will be polled as dynamic configuration sources. 2021-01-03 01:14:01.049 INFO 14841 --- [ main] c.n.c.sources.URLConfigurationSource : To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath. 2021-01-03 01:14:01.282 INFO 14841 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2021-01-03 01:14:02.512 INFO 14841 --- [ main] o.s.cloud.commons.util.InetUtils : Cannot determine local hostname 2021-01-03 01:14:03.823 INFO 14841 --- [ main] o.s.cloud.commons.util.InetUtils : Cannot determine local hostname 2021-01-03 01:14:03.856 WARN 14841 --- [ main] ockingLoadBalancerClientRibbonWarnLogger : You already have RibbonLoadBalancerClient on your classpath. It will be used by default. As Spring Cloud Ribbon is in maintenance mode. We recommend switching to BlockingLoadBalancerClient instead. In order to use it, set the value of `spring.cloud.loadbalancer.ribbon.enabled` to `false` or remove spring-cloud-starter-netflix-ribbon from your project. 2021-01-03 01:14:03.912 INFO 14841 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 2 endpoint(s) beneath base path '/actuator' 2021-01-03 01:14:03.957 INFO 14841 --- [ main] o.s.c.n.eureka.InstanceInfoFactory : Setting initial instance status as: STARTING 2021-01-03 01:14:04.055 INFO 14841 --- [ main] com.netflix.discovery.DiscoveryClient : Initializing Eureka in region us-east-1 2021-01-03 01:14:04.445 INFO 14841 --- [ main] c.n.d.provider.DiscoveryJerseyProvider : Using JSON encoding codec LegacyJacksonJson 2021-01-03 01:14:04.445 INFO 14841 --- [ main] c.n.d.provider.DiscoveryJerseyProvider : Using JSON decoding codec LegacyJacksonJson 2021-01-03 01:14:04.588 INFO 14841 --- [ main] c.n.d.provider.DiscoveryJerseyProvider : Using XML encoding codec XStreamXml 2021-01-03 01:14:04.588 INFO 14841 --- [ main] c.n.d.provider.DiscoveryJerseyProvider : Using XML decoding codec XStreamXml 2021-01-03 01:14:04.892 INFO 14841 --- [ main] c.n.d.s.r.aws.ConfigClusterResolver : Resolving eureka endpoints via configuration 2021-01-03 01:14:04.923 INFO 14841 --- [ main] com.netflix.discovery.DiscoveryClient : Disable delta property : false 2021-01-03 01:14:04.923 INFO 14841 --- [ main] com.netflix.discovery.DiscoveryClient : Single vip registry refresh property : null 2021-01-03 01:14:04.923 INFO 14841 --- [ main] com.netflix.discovery.DiscoveryClient : Force full registry fetch : false 2021-01-03 01:14:04.923 INFO 14841 --- [ main] com.netflix.discovery.DiscoveryClient : Application is null : false 2021-01-03 01:14:04.923 INFO 14841 --- [ main] com.netflix.discovery.DiscoveryClient : Registered Applications size is zero : true 2021-01-03 01:14:04.923 INFO 14841 --- [ main] com.netflix.discovery.DiscoveryClient : Application version is -1: true 2021-01-03 01:14:04.924 INFO 14841 --- [ main] com.netflix.discovery.DiscoveryClient : Getting all instance registry info from the eureka server 2021-01-03 01:14:05.208 INFO 14841 --- [ main] com.netflix.discovery.DiscoveryClient : The response status is 200 2021-01-03 01:14:05.211 INFO 14841 --- [ main] com.netflix.discovery.DiscoveryClient : Starting heartbeat executor: renew interval is: 30 2021-01-03 01:14:05.215 INFO 14841 --- [ main] c.n.discovery.InstanceInfoReplicator : InstanceInfoReplicator onDemand update allowed rate per min is 4 2021-01-03 01:14:05.221 INFO 14841 --- [ main] com.netflix.discovery.DiscoveryClient : Discovery Client initialized at timestamp 1609616645219 with initial instances count: 0 2021-01-03 01:14:05.222 INFO 14841 --- [ main] o.s.c.n.e.s.EurekaServiceRegistry : Registering application REST-SERVICE-CLIENT with eureka with status UP 2021-01-03 01:14:05.224 INFO 14841 --- [ main] com.netflix.discovery.DiscoveryClient : Saw local status change event StatusChangeEvent [timestamp=1609616645223, current=UP, previous=STARTING] 2021-01-03 01:14:05.226 INFO 14841 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_REST-SERVICE-CLIENT/localhost:rest-service-client: registering service... 2021-01-03 01:14:05.284 INFO 14841 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2021-01-03 01:14:05.286 INFO 14841 --- [ main] .s.c.n.e.s.EurekaAutoServiceRegistration : Updating port to 8080 2021-01-03 01:14:05.336 INFO 14841 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_REST-SERVICE-CLIENT/localhost:rest-service-client - registration status: 204 2021-01-03 01:14:06.297 INFO 14841 --- [ main] o.s.cloud.commons.util.InetUtils : Cannot determine local hostname 2021-01-03 01:14:06.320 INFO 14841 --- [ main] ServiceRegistrationAndDiscoveryClientApp : Started ServiceRegistrationAndDiscoveryClientApp in 11.053 seconds (JVM running for 11.884) 2021-01-03 01:14:15.010 INFO 14841 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2021-01-03 01:14:15.011 INFO 14841 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2021-01-03 01:14:15.024 INFO 14841 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 12 ms 2021-01-03 01:14:35.226 INFO 14841 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Disable delta property : false 2021-01-03 01:14:35.231 INFO 14841 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Single vip registry refresh property : null 2021-01-03 01:14:35.232 INFO 14841 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Force full registry fetch : false 2021-01-03 01:14:35.232 INFO 14841 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Application is null : false 2021-01-03 01:14:35.232 INFO 14841 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Registered Applications size is zero : true 2021-01-03 01:14:35.232 INFO 14841 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Application version is -1: false 2021-01-03 01:14:35.232 INFO 14841 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Getting all instance registry info from the eureka server 2021-01-03 01:14:35.408 INFO 14841 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : The response status is 200 ^C2021-01-03 01:15:43.115 INFO 14841 --- [extShutdownHook] o.s.c.n.e.s.EurekaServiceRegistry : Unregistering application REST-SERVICE-CLIENT with eureka with status DOWN 2021-01-03 01:15:43.118 WARN 14841 --- [extShutdownHook] com.netflix.discovery.DiscoveryClient : Saw local status change event StatusChangeEvent [timestamp=1609616743118, current=DOWN, previous=UP] 2021-01-03 01:15:43.118 INFO 14841 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_REST-SERVICE-CLIENT/localhost:rest-service-client: registering service... 2021-01-03 01:15:43.179 ERROR 14841 --- [nfoReplicator-0] c.n.d.s.t.d.RedirectingEurekaHttpClient : Request execution error. endpoint=DefaultEndpoint{ serviceUrl='http://localhost:8761/eureka/}
You can access the apps registered in the eureka server at : http://localhost:8761/eureka/apps/. The output is shown below:
You can access the services registered in the eureka server at : http://localhost:8080/service-instances/rest-service-client. The output is shown below:
2.5.2 HATEOAS
HATEOAS is Hypermedia As The Engine of Application state constraint. It is related to the discoverability of methods on the resource from Hypermedia Hypertext helps in replacing the documentation through the conversation. The HATEOAS representation helps in describing the API usage for clients. .The example for HATEOAS implementation can be accessed at this link.
3. Download the Source Code
You can download the full source code of this example here: RESTful Web Service Discovery