Home » Enterprise Java » spring » Boot » Spring Boot Microservices Example

About Joel Patrick Llosa

Joel Patrick Llosa
I graduated from Silliman University in Dumaguete City with a degree in Bachelor of Science in Business Computer Application. I have contributed to many Java related projects at University of Southampton (iSolutions), Predictive Technologies, LLC., Confluence Service, North Concepts, Inc., NEC Telecom Software Philippines, Inc., and NEC Technologies Philippines, Inc. You can also find me in Upwork freelancing as a Java Developer.

Spring Boot Microservices Example

Welcome to the Spring Boot Microservices Example. Microservices is popular because it allows large systems to be composed of smaller systems. Think of it like the single responsiblity principle. The smaller systems have a single responsibilty to the large system. In the monolithic approach, all the smaller systems are bunched up to make up one large system or one large appplication. The microservices approach breaks the large system into smaller chunks.

1. Assumptions

This article assumes that you know your way around Eclipse. You are familiar with Maven and Spring. This project has been created using Eclipse Mars so all instructions are based on this IDE. Download the example code, load it into Eclipse or your favorite IDE and let’s walk through the code.

2. Introduction

This is a simple Spring Boot Microservices example. This web application does nothing more but an arithmetic service. An arithmetic calculator served in a microservice approach. The diagram below shows our two microservices, Addition Server and Subtraction Server. The servers need to find each other so they need to register to the discovery server called Eureka. Once the Web Server finds the micro service, it can then send requests. In this example, the Web Server sends RESTful requests. When the Web Server receives the response it then serves the result to the browser.

Spring Boot Microservices Example - Diagram

Spring Boot Microservices Diagram

3. POM

The important parts of the POM are the following:

  • spring-boot-starter-parent – provide default configurations for our Spring Boot project
  • spring-boot-starter – setup Spring Boot
  • spring-boot-starter-web – setup Spring MVC and REST, use Embedded Tomcat
  • spring-boot-starter-thymeleaf – use Thymeleaf templating engine
  • spring-cloud-starter – setup Spring Cloud
  • spring-cloud-starter-netflix-eureka-server – Eureka for service registration
  • spring-cloud-dependencies – use the Finchley.RELEASE

4. Eureka Server

The code for the registration server is only a few lines. It really is this short.

EurekaServer.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
package com.javacodegeeks.example.registration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServer {
    public static void main(String[] args) {
        System.setProperty("spring.config.name", "eureka-server");
        SpringApplication.run(EurekaServer.class, args);
    }
}

@SpringBootApplication is a convenience annotation that is equivalent to declaraing @Configuration, @EnableAutoConfiguration, and @ComponentScan. The @EnableEurekaServer spins up a registry server that other applications can talk to. Line 11 tells Spring Boot to look for the file eureka-server.properties for its configuration.

eureka-server.properties

1
2
3
4
5
6
7
eureka.instance.hostname=localhost
eureka.client.registerWithEureka=false
eureka.client.fetchRegistry=false
server.port=1111
spring.thymeleaf.enabled=false

We’ll be running the Eureka Server on port 1111. The default is 8761. Indicating registerWithEureka as false stops the server from registering itself. We would register ourself when we are running multiple discory servers. Open up a command prompt and let’s run the Eureka Server. But first we must compile our project, execute mvn clean package. After successful compilation, run java -jar target/spring-boot-microservices-0.0.1-SNAPSHOT.jar eureka and you should see some standard Spring logging output in the console. Open your web browser, access http://localhost:1111/ and you should see something like below:

Spring Boot Microservices - Eureka Server

Eureka Server

5. Addition Server

This server provides the addition service. It simply adds two numbers.

AdditionServer.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.javacodegeeks.example.rest.addition;
import java.util.logging.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;
@EnableAutoConfiguration
@EnableDiscoveryClient
@ComponentScan
public class AdditionServer {
    protected Logger logger = Logger.getLogger(AdditionServer.class.getName());
    public static void main(String[] args) {
        System.setProperty("spring.config.name", "addition-server");
        SpringApplication.run(AdditionServer.class, args);
    }
}

@EnableAutoConfiguration defines this as a Spring Boot application. The @EnableDiscoveryClient enables service registration and discovery. The server registers itself with the discovery server provided in the configuration file. The registration with the discovery server makes this a microservice.

addition-server.properties

01
02
03
04
05
06
07
08
09
10
11
12
13
14
# Spring properties
spring.application.name=addition-service
spring.freemarker.enabled=false
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/addition-server/templates/
error.path: /error
# HTTP Server
server.port: 2222
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
eureka.client.instance.leaseRenewalIntervalInSeconds=5
management.endpoints.web.exposure.include='*'

As the cofiguration states, this microservice is named as addition-service. It will listen on port 2222. It will use the discovery server at http://localhost:1111/eureka/. leaseRenewalIntervalInSeconds for now is set to five but this is not recommended in production. By default the client refresh time is thirty seconds. By now you should have packaged the application. In case you have not, execute mvn clean package. After successful compilation, run java -jar target/spring-boot-microservices-0.0.1-SNAPSHOT.jar addition and you should see some standard Spring logging output in the console. To check if your microservices is up and running open your web browser, access http://localhost:2222/ and you should see a message saying “Addition Server Microservice is running”. Alternatively, you can access http://localhost:1111/eureka/apps/addition-service/ and you’ll receive an XML of the details of the addition service. Or you could check the Eureka Server page and the addition-service should be listed under instances currently registered with Eureka.

Below are additional source files required to run the Addition Server.

HomeController.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
package com.javacodegeeks.example.rest.addition;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HomeController {
    @RequestMapping("/")
    public String home() {
        return "index";
    }
}

The above controller simply directs requests to the root resource to index.html. All thymeleaf templates are found in src/main/resources. This particular template is located in src/main/resources/addition-server/templates.

AdditionController.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.javacodegeeks.example.rest.addition;
import java.util.logging.Logger;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AdditionController {
    protected Logger logger = Logger.getLogger(AdditionController.class
            .getName());
    @RequestMapping("/add")
    public String doAdd(@RequestParam(defaultValue="0") String addend1,
            @RequestParam(defaultValue="0") String addend2) {
        int augend1 = Integer.valueOf(addend1);
        int augend2 = Integer.valueOf(addend2);
        int sum = augend1 + augend2;
        return "{\"addend1\":\"" + addend1 + "\", \"addend2\":\"" + addend2 + "\", \"sum\": \"" + sum + "\"}";
    }
}

The doAdd method handles requests made on /add. It retrieves the parameters and adds them. It then returns a JSON string.

6. Subtraction Server

This server provides the subtraction service. It simply deducts a number from another number.

SubtractionServer.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
package com.javacodegeeks.example.rest.subtraction;
import java.util.logging.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;
@EnableAutoConfiguration
@EnableDiscoveryClient
@ComponentScan
public class SubtractionServer {
    protected Logger logger = Logger.getLogger(SubtractionServer.class.getName());
    public static void main(String[] args) {
        System.setProperty("spring.config.name", "subtraction-server");
        SpringApplication.run(SubtractionServer.class, args);
    }
}

The SubtractionServer.java is similar to the AdditionServer.java code. The only difference is the configuration.

subtraction-server.properties

01
02
03
04
05
06
07
08
09
10
11
12
13
14
# Spring properties
spring.application.name=subtraction-service
spring.freemarker.enabled=false
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/subtraction-server/templates/
error.path: /error
# HTTP Server
server.port: 3333
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
eureka.client.instance.leaseRenewalIntervalInSeconds=5
management.endpoints.web.exposure.include='*'

As the cofiguration states, this microservice is named as subtraction-service. It will listen on port 3333. It will use the discovery server at http://localhost:1111/eureka/. Run java -jar target/spring-boot-microservices-0.0.1-SNAPSHOT.jar subtraction and you should see some standard Spring logging output in the console. To check if your microservices is up and running open your web browser, access http://localhost:3333/ and you should see a message saying “Subtraction Server Microservice is running”. Or you could check the Eureka Server page and the subtraction-service should be listed under instances currently registered with Eureka. You can also access http://localhost:1111/eureka/apps/subtraction-service/ to get XML details of the service just like the addition server.

Below are additional source files required to run the Subtraction Server.

HomeController.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
package com.javacodegeeks.example.rest.subtraction;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HomeController {
    @RequestMapping("/")
    public String home() {
        return "index";
    }
}

The above controller simply directs requests to the root resource to index.html. All thymeleaf templates are found in src/main/resources. This particular template is located in src/main/resources/subtraction-server/templates.

SubtractionController.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.javacodegeeks.example.rest.subtraction;
import java.util.logging.Logger;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SubtractionController {
    protected Logger logger = Logger.getLogger(SubtractionController.class
            .getName());
    @RequestMapping("/subtract")
    public String doSubtract(@RequestParam(defaultValue="0") String minuend,
            @RequestParam(defaultValue="0") String subtrahend) {
        int m = Integer.valueOf(minuend);
        int s = Integer.valueOf(subtrahend);
        int difference = m - s;
        return "{\"minuend\":\"" + minuend + "\", \"subtrahend\":\"" + subtrahend + "\", \"difference\": \"" + difference + "\"}";
    }
}

The doSubtract method handles requests made on /subtract. It retrieves the parameters and subtracts them. It then returns a JSON string.

7. Web Server

This server serves web pages to the browser. This server uses the microservices. Since this article is about microservices, we will not go into detail on how to serve web content with Spring MVC.

WebServer.java

01
02
03
04
05
06
07
08
09
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
package com.javacodegeeks.example.web;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient
@ComponentScan(useDefaultFilters = false)
public class WebServer {
    public static final String ADDITION_SERVICE_URL = "http://addition-service";
    public static final String SUBTRACTION_SERVICE_URL = "http://subtraction-service";
    public static void main(String[] args) {
        System.setProperty("spring.config.name", "web-server");
        SpringApplication.run(WebServer.class, args);
    }
    @LoadBalanced
    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
    @Bean
    public WebAdditionService additionService() {
        return new WebAdditionService(ADDITION_SERVICE_URL);
    }
    @Bean
    public WebArithmeticController additionController() {
        return new WebArithmeticController(additionService(), subtractionService());
    }
    @Bean
    public WebSubtractionService subtractionService() {
        return new WebSubtractionService(SUBTRACTION_SERVICE_URL);
    }
    @Bean
    public HomeController homeController() {
        return new HomeController();
    }
}

@SpringBootApplication is a convenience annotation that is equivalent to declaraing @Configuration, @EnableAutoConfiguration, and @ComponentScan. The @EnableDiscoveryClient enables service registration and discovery. The @ComponentScan(useDefaultFilters = false) indicates whether automatic detection of classes annotated with @Component, @Repository, @Service, or @Controller should be enabled.

@LoadBalanced marks RestTemplate< to be configured to use a LoadBalancerClient. This means the RestTemplate bean will be auto-configured by Spring Cloud to use a custom HttpRequestClient that uses Netflix Ribbon to do the microservices lookup. Ribbon is also a load-balancer. If you have multiple instances of a service available, Ribbon picks one for you.

web-server.properties

01
02
03
04
05
06
07
08
09
10
11
12
13
14
spring.application.name=web-service
spring.freemarker.enabled=false
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/web-server/templates/
error.path=/error
server.port:4444
eureka.client.serviceUrl.defaultZone:http://localhost:1111/eureka
eureka.instance.leaseRenewalIntervalInSeconds:5
    
management.endpoints.web.exposure.include='*'
 

As the cofiguration states, the application name is web-service. It will listen on port 4444. It will use the discovery server at http://localhost:1111/eureka/. Open up a command prompt and run java -jar target/spring-boot-microservices-0.0.1-SNAPSHOT.jar web. After some standard Spring logging, you should be able to access the web server at http://localhost:4444/. By this time, we have four open command prompts running four servers simultaneously. The web server page looks like the one below.

Spring Boot Microservices - Web Server

Web Server

And your Eureka server will have all three services registered as you can see below.

Spring Boot Microservices Example Eureka List

Spring Boot Microservices Example Eureka List

Below are additional source files required to run the Web Server.

HomeController.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
package com.javacodegeeks.example.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HomeController {
    @RequestMapping("/")
    public String home() {
        return "index";
    }
}

The above controller simply directs requests to the root resource to index.html. All thymeleaf templates are found in src/main/resources. This particular template is located in src/main/resources/web-server/templates.

WebArithmeticController.java

01
02
03
04
05
06
07
08
09
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
package com.javacodegeeks.example.web;
import java.util.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class WebArithmeticController {
    @Autowired
    protected WebAdditionService additionService;
    @Autowired
    protected WebSubtractionService subtractionService;
    protected Logger logger = Logger.getLogger(WebArithmeticController.class
            .getName());
    public WebArithmeticController(WebAdditionService additionService, WebSubtractionService subtractionService) {
        this.additionService = additionService;
        this.subtractionService = subtractionService;
    }
    @RequestMapping("/add")
    public String doAdd(@RequestParam(defaultValue="0") String addend1,
            @RequestParam(defaultValue="0") String addend2,
            Model model) {
        String sum = additionService.add(addend1, addend2);
        logger.info("Sum: " + sum);
        model.addAttribute("json", sum);
        return "sum";
    }
    @RequestMapping("/subtract")
    public String doSubtract(@RequestParam(defaultValue="0") String minuend,
            @RequestParam(defaultValue="0") String subtrahend,
            Model model) {
        String difference = subtractionService.subtract(minuend, subtrahend);
        logger.info("Difference: " + difference);
        model.addAttribute("json", difference);
        return "difference";
    }
}

The doAdd method handles requests made on /add. It retrieves the parameters and passes it to the additionService object which was automatically injected by Spring. It then returns the sum.html template. The doSubtract method handles requests made on /subtract. It retrieves the parameters and passes it to the subtractionService object which was automatically injected by Spring. It then returns the difference.html template. The service classes are discussed in the next section.

8. Accessing the Microservices

WebAdditionService.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.javacodegeeks.example.web;
import java.util.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class WebAdditionService {
    @Autowired
    @LoadBalanced
    protected RestTemplate restTemplate;
    protected String serviceUrl;
    protected Logger logger = Logger.getLogger(WebAdditionService.class
            .getName());
    public WebAdditionService(String serviceUrl) {
        this.serviceUrl = serviceUrl.startsWith("http") ? serviceUrl
                : "http://" + serviceUrl;
    }
    public String add(String addend1, String addend2) {
        return restTemplate.getForObject(serviceUrl + "/add?addend1={addend1}&addend2={addend2}", String.class, addend1, addend2);
    }
}

WebSubtractionService.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.javacodegeeks.example.web;
import java.util.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class WebSubtractionService {
    @Autowired
    @LoadBalanced
    protected RestTemplate restTemplate;
    protected String serviceUrl;
    protected Logger logger = Logger.getLogger(WebSubtractionService.class
            .getName());
    public WebSubtractionService(String serviceUrl) {
        this.serviceUrl = serviceUrl.startsWith("http") ? serviceUrl
                : "http://" + serviceUrl;
    }
    public String subtract(String minuend, String subtrahend) {
        return restTemplate.getForObject(serviceUrl + "/subtract?minuend={minuend}&subtrahend={subtrahend}", String.class, minuend, subtrahend);
    }
}

The above classes are similar. Both are annotated with @Service. This indicates that the class is a service which is an operation offered as an interface that stands alone in the model, with no encapsulated state. This annotation serves as a specialization of @Component, allowing for implementation classes to be autodetected through classpath scanning. RestTemplate is load balanced as explained above. The serviceUrl is provided by the main program. The restTemplate returns a JSON string which is displayed by the web server.

9. Running the Spring Boot Microservices Example

Execute mvn clean package to create the fat jar. For conveniece, we have a fat jar whose start class is com.javacodegeeks.example.Main. Just provide the arguments eureka, addition, substraction, or web to run the respective servers.

Main.java

01
02
03
04
05
06
07
08
09
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
package com.javacodegeeks.example;
import com.javacodegeeks.example.registration.EurekaServer;
import com.javacodegeeks.example.rest.addition.AdditionServer;
import com.javacodegeeks.example.rest.subtraction.SubtractionServer;
import com.javacodegeeks.example.web.WebServer;
public class Main {
    public static void main(String[] args) {
        String serverName = "";
        switch (args.length) {
        case 2:
            System.setProperty("server.port", args[1]);
        case 1:
            serverName = args[0].toLowerCase();
            break;
        default:
            return;
        }
        if (serverName.equals("eureka")) {
            EurekaServer.main(args);
        } else if (serverName.equals("addition")) {
            AdditionServer.main(args);
        } else if (serverName.equals("subtraction")) {
            SubtractionServer.main(args);
        } else if (serverName.equals("web")) {
            WebServer.main(args);
        } else {
            System.out.println("Unknown server type: " + serverName);
        }
    }
}

It is easier to run the different applications by running them from the command line with different windows. It will be eaiser to see their log output.

  • java -jar target/spring-boot-microservices-0.0.1-SNAPSHOT.jar eureka – executes the eureka server
  • java -jar target/spring-boot-microservices-0.0.1-SNAPSHOT.jar addition – executes the addition server
  • java -jar target/spring-boot-microservices-0.0.1-SNAPSHOT.jar subtraction – executes the subtraction server
  • java -jar target/spring-boot-microservices-0.0.1-SNAPSHOT.jar web – executes the web server

10. Summary

In summary, the discovery server is started up first. Then the microservices and the web server register to the discovery server in order for them to find each other. Once the web server knows where to find the microservices, it can then issue RESTful requests to the microservices. The web server performs its task aided by the microservices. The process is made simple and easy with the help of Spring.

11. Download the Source Code

This is an example about Spring Boot Microservices.

Download
You can download the source code of this example here: Spring Boot Microservices Example.
(+2 rating, 2 votes)
Start the discussion Views Tweet it!

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

 

1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial

5. Java Interview Questions

6. Spring Interview Questions

7. Android UI Design

 

and many more ....

 

Receive Java & Developer job alerts in your Area

 

Leave a Reply

avatar
  Subscribe  
Notify of