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.

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:
- Setup Eureka
- Setup Zuul
- Create a sample microservice
- Run all these Spring Boot apps
- 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:

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>89 <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>89 <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>1516 <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>2122 <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>3233 <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>4445 <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 @SpringBootApplication2public 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 run2spring.application.name=cloud-eureka3server.port=900145# Set Eureka server url here, and since this app is the Eureka server - make sure it doesn't register itself6eureka.client.serviceUrl.defaultZone=http://localhost:9001/eureka7eureka.client.register-with-eureka=false8eureka.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>89 <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>1516 <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>2122 <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>3637 <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>4849 <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 @SpringBootApplication2public 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 run2spring.application.name=cloud-zuul3server.port=900245# Set Eureka server url here6eureka.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 @EnableEurekaClient2public class ServiceSampleApplication {3 public static final String APPLICATION_ID = IdGenerator.uuid();45 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@RestController2public 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-sample3server.port=045# Set Eureka server url here, and specify Eureka instance ID generation pattern6eureka.client.serviceUrl.defaultZone=http://localhost:9001/eureka7eureka.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.

Eureka home page

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.

Eureka home page with Zuul instance launched

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.

Eureka home page with Zuul and sample service running

Checking service’s ping via direct url

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.

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

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: