Navigate back to the homepage

Quickstart with Java Spring Boot mircoservices

Leo Ertuna
November 12th, 2020 · 3 min read

Hello everyone, and welcome! In today’s tutorial I wanted to cover one simple, practical and probably most widely used way to build your microservice architecture with Java.

This is gonna be like a “hello world” tutorial but for microservices. I will show how you can quickly setup your own Java cloud environment from scratch and get started with your project.

1

Main pieces of our environment will be Eureka (GitHub) — a service registry, and Zuul (GitHub) — a router / load balancer. Since I will be covering only basics of how to get them up and running, please check other resources to learn more details about Eureka & Zuul, how they can be setup, optimized and used in your case. For our sample microservice itself — we will create a demo Spring Boot app, with one REST API endpoint. This should be enough to give you an idea of how Spring Boot application works, and you can add your own REST APIs & service logic later on.

Our goals for today:

  1. Setup Eureka
  2. Setup Zuul
  3. Create a sample microservice
  4. Run all these Spring Boot apps
  5. Try out how we can call our services, and how load balancing works between multiple instances of this service

Part 0 — Project structure

Although services should be ideally split into different projects, with their own git repositories, for the purpose of this example we will use one project, with a parent module that will contain all services and other modules. In the end we will have a project structure looking like this:

2

Project structure

Forgive me for skipping over obvious things, like installing JDK, setting up Maven and etc., I assume that people who stumble upon articles about microservices already have some experience with Java & Spring.

Let’s start by creating this parent module, with pom.xml:

1<?xml version="1.0" encoding="UTF-8"?>
2<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">
3 <modelVersion>4.0.0</modelVersion>
4 <groupId>com.example.microservices</groupId>
5 <artifactId>parent</artifactId>
6 <version>1.0-SNAPSHOT</version>
7 <packaging>pom</packaging>
8
9 <modules>
10 <!-- Will be filled with child modules-->
11 </modules>
12</project>

There’s not much in it than that, with the initial parent module created we can start adding our services.


Part 1 — Eureka

Let’s create a new module cloud-eureka inside our parent, with the following pom.xml, which basically says that this is a Spring Boot application with Eureka server and Actuator enabled:

1<?xml version="1.0" encoding="UTF-8"?>
2<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">
3 <modelVersion>4.0.0</modelVersion>
4 <groupId>com.example.microservices</groupId>
5 <artifactId>cloud-eureka</artifactId>
6 <version>1.0-SNAPSHOT</version>
7 <packaging>jar</packaging>
8
9 <parent>
10 <groupId>org.springframework.boot</groupId>
11 <artifactId>spring-boot-starter-parent</artifactId>
12 <version>2.3.5.RELEASE</version>
13 <relativePath/>
14 </parent>
15
16 <properties>
17 <java.version>1.8</java.version>
18 <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
19 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
20 </properties>
21
22 <dependencies>
23 <dependency>
24 <groupId>org.springframework.cloud</groupId>
25 <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
26 </dependency>
27 <dependency>
28 <groupId>org.springframework.boot</groupId>
29 <artifactId>spring-boot-starter-actuator</artifactId>
30 </dependency>
31 </dependencies>
32
33 <dependencyManagement>
34 <dependencies>
35 <dependency>
36 <groupId>org.springframework.cloud</groupId>
37 <artifactId>spring-cloud-dependencies</artifactId>
38 <version>${spring-cloud.version}</version>
39 <type>pom</type>
40 <scope>import</scope>
41 </dependency>
42 </dependencies>
43 </dependencyManagement>
44
45 <build>
46 <plugins>
47 <plugin>
48 <groupId>org.springframework.boot</groupId>
49 <artifactId>spring-boot-maven-plugin</artifactId>
50 </plugin>
51 </plugins>
52 </build>
53</project>

Then we’ll add one piece of Java code, CloudEurekaApplication.java which acts as a starting point for Eureka application, again we specify that this is a @SpringBootApplication and that it needs to @EnableEurekaServer with these annotations:

1@EnableEurekaServer @SpringBootApplication
2public class CloudEurekaApplication {
3 public static void main(String[] args) {
4 SpringApplication.run(CloudEurekaApplication.class, args);
5 }
6}

Now we need to add application.properties for this Spring Boot app:

1# Specify application name, and port on which this app should run
2spring.application.name=cloud-eureka
3server.port=9001
4
5# Set Eureka server url here, and since this app is the Eureka server - make sure it doesn't register itself
6eureka.client.serviceUrl.defaultZone=http://localhost:9001/eureka
7eureka.client.register-with-eureka=false
8eureka.client.fetch-registry=false

That’s it with Eureka, now to our proxy.


Part 2 — Zuul

The second step of our cloud environment will be a Zuul proxy service. This setup follows the same idea as Eureka application from the previous step, it’s a Spring Boot app with Zuul dependency. The only difference is that this time Zuul application will become our first client of Eureka registry.

So Zuul’s pom.xml will be:

1<?xml version="1.0" encoding="UTF-8"?>
2<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">
3 <modelVersion>4.0.0</modelVersion>
4 <groupId>com.example.microservices</groupId>
5 <artifactId>cloud-zuul</artifactId>
6 <version>1.0-SNAPSHOT</version>
7 <packaging>jar</packaging>
8
9 <parent>
10 <groupId>org.springframework.boot</groupId>
11 <artifactId>spring-boot-starter-parent</artifactId>
12 <version>2.3.5.RELEASE</version>
13 <relativePath/>
14 </parent>
15
16 <properties>
17 <java.version>1.8</java.version>
18 <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
19 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
20 </properties>
21
22 <dependencies>
23 <dependency>
24 <groupId>org.springframework.cloud</groupId>
25 <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
26 </dependency>
27 <dependency>
28 <groupId>org.springframework.cloud</groupId>
29 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
30 </dependency>
31 <dependency>
32 <groupId>org.springframework.boot</groupId>
33 <artifactId>spring-boot-starter-actuator</artifactId>
34 </dependency>
35 </dependencies>
36
37 <dependencyManagement>
38 <dependencies>
39 <dependency>
40 <groupId>org.springframework.cloud</groupId>
41 <artifactId>spring-cloud-dependencies</artifactId>
42 <version>${spring-cloud.version}</version>
43 <type>pom</type>
44 <scope>import</scope>
45 </dependency>
46 </dependencies>
47 </dependencyManagement>
48
49 <build>
50 <plugins>
51 <plugin>
52 <groupId>org.springframework.boot</groupId>
53 <artifactId>spring-boot-maven-plugin</artifactId>
54 </plugin>
55 </plugins>
56 </build>
57</project>

The only Java class will be CloudZuulApplication.java. Notice the @EnableEurekaClient annotation, which marks that this app should register itself in Eureka:

1@EnableZuulProxy @EnableEurekaClient @SpringBootApplication
2public class CloudZuulApplication {
3 public static void main(String[] args) {
4 SpringApplication.run(CloudZuulApplication.class, args);
5 }
6}

And finally application.properties of Zuul’s Spring Boot app:

1# Specify application name, and port on which this app should run
2spring.application.name=cloud-zuul
3server.port=9002
4
5# Set Eureka server url here
6eureka.client.serviceUrl.defaultZone=http://localhost:9001/eureka

Part 3 — Sample service

Before diving into our microservices it’s always a good idea to define some common modules that should be shared across your services. We will go on and add common and message-protocol modules, I won’t cover them in details here, you can look up what went into them (nothing interesting really) in the GitHub repository, link at the end of this article.

As usual we will need the main application class for our service, ServiceSampleApplication.java:

1@SpringBootApplication @EnableEurekaClient
2public class ServiceSampleApplication {
3 public static final String APPLICATION_ID = IdGenerator.uuid();
4
5 public static void main(String[] args) {
6 SpringApplication.run(ServiceSampleApplication.class, args);
7 }
8}

And a simple Spring’s @RestController, PingResource.java to define a REST API endpoint that we will use to test this service:

1@RestController
2public class PingResource {
3 @RequestMapping(value = "/ping", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
4 public @ResponseBody PingMO ping() {
5 return new PingMO(IdGenerator.uuid(), true, ServiceSampleApplication.APPLICATION_ID);
6 }
7}

Now in Spring’s application.properties we will make the service launch with a random port, and we will set a custom pattern for Eureka’s instance ID. These tweaks will allow us to launch multiple instances of this service in the same environment without any configuration changes:

1# Specify application name, and port on which this app should run (port 0 means that the port will be randomly assigned)
2spring.application.name=service-sample
3server.port=0
4
5# Set Eureka server url here, and specify Eureka instance ID generation pattern
6eureka.client.serviceUrl.defaultZone=http://localhost:9001/eureka
7eureka.instance.instance-id=${spring.application.name}:${spring.application.instance_id:${random.value}}

Part 4 — Running them all

First start Eureka application, wait for it to finish initializing and go to http://localhost:9001/ to visit Eureka home page, and http://localhost:9001/actuator/health to see the Spring Boot Actuator’s status.

3

Eureka home page

4

Eureka actuator health

After that you can launch Zuul, wait for it to initialize, and refresh Eureka’s home page. If everything went well you should see Zuul’s instance running there. And of course don’t forget to check http://localhost:9002/actuator/health too.

5

Eureka home page with Zuul instance launched

6

Zuul actuator health

Finally we can deploy the service itself. Same deal as with Zuul, run the Spring Boot app, wait for it to initialize, check Eureka’s home page. Now when the service is deployed it can be accessed in two ways: 1) directly via http://localhost:49674/ping but keep in mind that port is generated randomly, and your port will differ from what I got, or 2) via Zuul proxy http://localhost:9002/service-sample/ping using Spring’s application name property to specify which service you are calling.

7

Eureka home page with Zuul and sample service running

8

Checking service’s ping via direct url

9

Checking service’s ping via Zuul url

If you will need multiple instances of your services running — Eureka and Zuul will automatically take care of load balancing, you just need to launch a new instance of your service, and use the Zuul’s proxy url for requests.

10

Eureka home page with Zuul and 2 instances of sample service running

11

Load balancing between 2 deployed service instances

Looks easy enough? If you’re writing a client library that consumes your REST API be sure to always use the proxy url, and then the load balancing will happen automatically behind the scenes.


That’s it for now, I think we’ve covered enough of the backbone structure to quickly bootstrap your microservices architecture, and I hope this example will help you in your projects.

GitHub repo with source code for this tutorial


In case you’d like to check my other work or contact me:

More articles from TekLeo

Building a microservice for image super-scaling

This tutorial presents an example of how you can wrap any AI related solutions in a convenient stateless service

October 3rd, 2020 · 3 min read

How to automatically deskew (straighten) a text image using OpenCV

Today I would like to share with you a simple solution to image deskewing problem (straightening a rotated image) with Python and OpenCV

September 5th, 2020 · 3 min read
© 2020–2022 TekLeo
Link to $https://tekleo.net/Link to $https://github.com/jpleorxLink to $https://medium.com/@leo.ertunaLink to $https://www.linkedin.com/in/leo-ertuna-14b539187/Link to $mailto:leo.ertuna@gmail.com