In this Microservices Architecture Spring Boot tutorial, we will discuss to creating a microservices with spring and will see microservices architecture. Microservices allow large systems to be built up from a number of collaborating components. Microservices allows doing loose coupling between application processes instead of loose coupling between application components as Spring does.
Spring 5 Design Pattern Book
Microservices Architecture Spring Boot Table of Contents
- Introduction
- Microservices Benefits
- Microservices Challenges
- Microservices Infrastructure
- Microservices Tooling Supports
- Developing Simple Microservices Example
- Summary
1. Introduction
Microservices is not a new term. It coined in 2005 by Dr Peter Rodgers then called micro web services based on SOAP. It became more popular since 2010. Microservices allows us to break our large system into the number of independent collaborating processes. Let us see below microservices architecture.
1.1 What is Microservices Architecture?
Microservices architecture allows avoiding monolith application for the large system. It provides loose coupling between collaborating processes which running independently in different environments with tight cohesion. So let’s discuss it by an example as below.
For example imagine an online shop with separate microservices for user-accounts, product-catalog order-processing and shopping carts. So these components are inevitably important for such a large online shopping portal. For online shopping system, we could use following architectures.
1.2 Shopping system without Microservices (Monolith architecture)
In this architecture we are using Monolith architecture i.e. all collaborating components combine all in one application.
1.3 Shopping system with Microservices
In this architecture style, the main application divided into a set of sub-applications called microservices. One large Application divided into multiple collaborating processes as below.
Spring enables separation-of-concerns
- Loose Coupling– Effect of changes isolated
- Tight Cohesion– Code perform a single well-defined task
Microservices provide the same strength as Spring provide
- Loose Coupling– Application build from collaboration services or processes, so any process change without affecting another process.
- Tight Cohesion-An individual service or process that deals with a single view of data.
There are a number of moving parts that you have to set up and configure to build such a system. For implementing this system is not too obvious you have to know about spring boot, spring cloud and Netflix. In this post, I will discuss one example for this architecture before the example lets first discuss pros and cons of microservices architecture.
Popular Tutorials
2. Microservices Benefits
- The smaller code base is easy to maintain.
- Easy to scale as an individual component.
- Technology diversity i.e. we can mix libraries, databases, frameworks etc.
- Fault isolation i.e. a process failure should not bring the whole system down.
- Better support for smaller and parallel team.
- Independent deployment
- Deployment time reduce
3. Microservices Challenges
- Difficult to achieve strong consistency across services
- ACID transactions do not span multiple processes.
- Distributed System so hard to debug and trace the issues
- Greater need for an end to end testing
- Required cultural changes in across teams like Dev and Ops working together even in the same team.
4. Microservices Infrastructure
- Platform as a Service like Pivotal Cloud Foundry help to deployment, easily run, scale, monitor etc.
- It supports for continuous deployment, rolling upgrades fo new versions of code, running multiple versions of the same service at same time.
5. Microservices Tooling Supports
5.1 Using Spring for creating Microservices
- Setup new service by using Spring Boot
- Expose resources via a RestController
- Consume remote services using RestTemplate
5.2 Adding Spring Cloud and Discovery server
What is Spring Cloud?
- It is building blocks for Cloud and Microservices
- It provides microservices infrastructure like provide use services such as Service Discovery, a Configuration server and Monitoring.
- It provides several other open source projects like Netflix OSS.
- It provides PaaS like Cloud Foundry, AWS and Heroku.
- It uses Spring Boot style starters
There are many use-cases supported by Spring Cloud like Cloud Integration, Dynamic Reconfiguration, Service Discovery, Security, Client-side Load Balancing etc. But in this post we concentrate on following microservices support
- Service Discovery (How do services find each other?)
- Client-side Load Balancing (How do we decide which service instance to use?)
Service Discovery
Problem without discovery
- How do services find each other?
- What happens if we run multiple instances for a service
Resolution with service discovery
Implementing Service Discovery
Spring Cloud support several ways to implement service discovery but for this, I am going to use Eureka created by Netflix. Spring Cloud provides several annotation to make it use easy and hiding lots of complexity.
Client-side Load Balancing
Each service typically deployed as multiple instances for fault tolerance and load sharing. But there is the problem how to decide which instance to use?
Implementing Client-Side Load Balancing
We will use Netflix Ribbon, it provides several algorithms for Client-Side Load Balancing. Spring provides smart RestTemplate for service discovery and load balancing by using @LoadBalanced annotation with RestTemplate instance.
@ImageSource-Spring.io
6. Developing Simple Microservices Example
To build a simple microservices system following steps required
- Creating Discovery Service (Creating Eureka Discovery Service)
- Creating MicroService (the Producer)
- Register itself with Discovery Service with logical service.
- Create Microservice Consumers find Service registered with Discovery Service
- Discovery client using a smart RestTemplate to find microservice.
Maven Dependencies
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
Step 1: Creating Discovery Service (Creating Eureka Discovery Service)
- Eureka Server using Spring Cloud
- We need to implement our own registry service as below.
application.yml
# Configure this Discovery Server eureka: instance: hostname: localhost client: #Not a client registerWithEureka: false fetchRegistry: false # HTTP (Tomcat) port server: port: 1111
DiscoveryMicroserviceServerApplication.java
package com.doj.discovery; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class DiscoveryMicroserviceServerApplication { public static void main(String[] args) { SpringApplication.run(DiscoveryMicroserviceServerApplication.class, args); } }
pom.xml
<!-- Eureka registration server --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency>
For Whole Source Code for the Discover Server Application, you could download from GitHub as below link.
Run this Eureka Server application with right click and run as Spring Boot Application and open in browser http://localhost:1111/
Step 2: Creating Account Producer MicroService
Microservice declares itself as an available service and register to Discovery Server created in Step 1.
- Using @EnableDiscoveryClient
- Registers using its application name
Let’s see the service producer application structure as below.
application.yml
### Spring properties # Service registers under this name spring: application: name: accounts-microservice # Discovery Server Access eureka: client: serviceUrl: defaultZone: http://localhost:1111/eureka/ # HTTP Server (Tomcat) Port server: port: 2222 # Disable Spring Boot's "Whitelabel" default error page, so we can use our own error: whitelabel: enabled: false
AccountsMicroserviceServerApplication.java
package com.doj.ms.accounts; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class AccountsMicroserviceServerApplication { public static void main(String[] args) { SpringApplication.run(AccountsMicroserviceServerApplication.class, args); } }
pom.xml
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
Other required source files related to this application you could download from GitHub link as given below
Now run this account service application as Spring Boot application and after few seconds refresh the browser to the home page of Eureka Discovery Server at http://localhost:1111/ in previous Step 1. Now one Service registered to the Eureka registered instances with Service Name “ACCOUNT-MICROSERVICE” as below
Step 3: Consumer Service
- Create Consumers to find the Producer Service registered with Discovery Service at Step 1.
- @EnableDiscoveryClient annotation also allows us to query Discovery server to find microservices.
Let’s see the consumer application structure as below.
application.yml
# Service registers under this name # Control the InternalResourceViewResolver: spring: application: name: accounts-web mvc: view: prefix: /WEB-INF/views/ suffix: .jsp # Discovery Server Access eureka: client: serviceUrl: defaultZone: http://localhost:1111/eureka/ # Disable Spring Boot's "Whitelabel" default error page, so we can use our own error: whitelabel: enabled: false
WebclientMicroserviceServerApplication.java
package com.doj.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.web.client.RestTemplate; @SpringBootApplication @EnableDiscoveryClient public class WebclientMicroserviceServerApplication { public static final String ACCOUNTS_SERVICE_URL = "http://ACCOUNTS-MICROSERVICE"; public static void main(String[] args) { SpringApplication.run(WebclientMicroserviceServerApplication.class, args); } @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } @Bean public AccountRepository accountRepository(){ return new RemoteAccountRepository(ACCOUNTS_SERVICE_URL); } }
pom.xml
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- These dependencies enable JSP usage --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency> </dependencies>
Other required source files related to this application you could download from GitHub link as given below
web client-microservice-server
Now run this consumer service application as Spring Boot application and after few seconds refresh the browser to the home page of Eureka Discovery Server at http://localhost:1111/ in previous Step 1. Now one more Service registered to the Eureka registered instances with Service Name “ACCOUNTS-WEB” as below
Lets our consumer consume the service of producer registered at discovery server.
package com.doj.web; import java.util.Arrays; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.client.RestTemplate; /** * @author Dinesh.Rajput * */ public class RemoteAccountRepository implements AccountRepository { @Autowired protected RestTemplate restTemplate; protected String serviceUrl; public RemoteAccountRepository(String serviceUrl) { this.serviceUrl = serviceUrl.startsWith("http") ? serviceUrl : "http://" + serviceUrl; } @Override public List<Account> getAllAccounts() { Account[] accounts = restTemplate.getForObject(serviceUrl+"/accounts", Account[].class); return Arrays.asList(accounts); } @Override public Account getAccount(String number) { return restTemplate.getForObject(serviceUrl + "/accounts/{id}", Account.class, number); } }
Let’s open web application which is a consumer of the account microservice registered at Eureka Discovery Server.
http://localhost:8080/ as below
Now click on View Account List then fetch all accounts from account microservice.
http://localhost:8080/accountList
Now click on any account from the list of accounts to fetch the details of the account for account number from account microservice.
http://localhost:8080/accountDetails?number=5115
Load Balanced RestTemplate
Create using @LoadBalanced– Spring enhances it to service lookup & load balancing
@Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); }
Must inject using the same qualifier-
- If there are multiple RestTemplate you get the right one.
- It can be used to access multiple microservices
@Autowired @LoadBalanced protected RestTemplate restTemplate;
Load Balancing with Ribbon
Our smart RestTemplate automatically integrates two Netflix utilities
- Eureka Service Discovery
- Ribbon Client Side Load Balancer
Eureka returns the URL of all available instances
Ribbon determine the best available service too use
Just inject the load balanced RestTemplate automatic lookup by logical service-name
7. Summary
After completion of this article you should have learned:
- What is the MicroServices Architecture
- Advantages and Challenges of MicroServices
- And some information about Spring Cloud such as Eureka Discover Server by Netflix and Ribbon.
Spring Boot Related Topics
- Spring Boot Interview Questions and Answers
- Introduction to Spring Boot
- Essentials and Key Components of Spring Boot
- Spring Boot CLI Installation and Hello World Example
- Spring Boot Initializr Web Interface
- Spring Boot Initializr With IDEs
- Spring Boot Initializr With Spring Boot CLI
- Installing Spring Boot
- Developing your first Spring Boot application
- External Configurations for Spring Boot Applications
- Logging Configuration in Spring Boot
- Spring Boot and Spring MVC
- Working with SQL Databases and Spring Boot
- MySQL Configurations
- Spring Data JPA using Spring Boot Application
- Spring Boot with NoSQL technologies
- Spring Cache Tutorial
- Spring Security Tutorial with Spring Boot
- Spring Boot and MongoDB in REST Application
- Complete Guide for Spring Boot Actuator
- Microservices with Spring Boot
Is Git code for the above example?
Thank you for your effort
Plz revise what you wrote under “Microservices Infrastructure”
Hi Sir,
i have need source code for spring boot with microservices with view jsp page.
and how to integrate microservices with view page.
How can we run spring web application(com.doj.web) using SpringBoot ?
I see following issue
”
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Fri Mar 30 15:27:56 IST 2018
There was an unexpected error (type=Not Found, status=404).
/WEB-INF/views/index.jsp
“
Hi.. I tried to execute your code , it worked fine. Similarly I added one more microservice provider and added its configuration in discover server. whenever i try to access that another service it doesnt get call. I can see two different microservice instances in eureka.
Good work sir …. keep it up , it helped me to understand Microservices . Thanks
Somehow I keep getting 404 null when I click on AccountList link.
org.springframework.web.client.httpclienterrorexception 404 null
What am I missing?
add this to your boot class – @SpringBootApplication(exclude = {ErrorMvcAutoConfiguration.class})
Hi, i need the source code to develop my project with micro services.
Thank you sir …. , it helped me to understand Micro services .
I am not able to run accounts/ webclient services. I get the following issue:
java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
Nice code example demonstrating the concept, Dinesh. However, the code does not work – I don’t know how its working in your/ other’s case. When I run the client service, the target endpoint returns null (the endpoint uri is not resolved), specifically ACCOUNTS_SERVICE_URL. I am not sure how the endpoint URI formed is even valid one. For example, as per your code, the endpoint url “getAllAccounts()” resolves to http://ACCOUNTS-MICROSERVICE/accounts, which is not a valid url- am I right?
Also, on closer look, it seems the Eureka client api is missing – which’s a glue code & the crux of this exercise. When I modified the RemoteAccountRepository.getAllAccounts(), it worked fine.:
@Override
public List getAllAccounts() {
Application application = eurekaClient.getApplication(ACCOUNTS_SERVICE_URL);
InstanceInfo instanceInfo = application.getInstances().get(0);
this.serviceUrl = “http://” + instanceInfo.getIPAddr() + “:” + instanceInfo.getPort()
Account[] accounts = restTemplate.getForObject(serviceUrl+”/accounts”, Account[].class);
return Arrays.asList(accounts);
}
Please clarify and update the code example accordingly.
Excellent tutorial. learned a lot Many thanks dear dinesh
Git code is available in the example, please check.
Hi, thanks for reading this article.
Is it something wrong written under this section?
Hi Dhiraj,
The code is available with this example, please check GIT.
Please check views folder and index.jsp must be there. And also check properties file.
Hi Aditi,
You can use RestTemplate or Feign for communicating two microservices each other.
Thanks Manish.
Hi Pradeep,
The code is available with this example, please check.
Thanks, Sanatan.
Thanks, Mahesh for reading this article.
Yes, it is working if you have registered all microservices with Eureka Server.
Your code is also fine.
Thanks, Bhimesh for reading this article.
Nice Tutorial. Learnt so much. I have a question. Able to see eureka server, able to register two micro services to discovery server. I am trying to open http://localhost:8080. But its giving error. I know, this might be a silly question not sure why its not working for me. I think, this should work by default as its a tomcat port. Please help me.
May I get Git link?
Hi Dinesh, Thanks for your tutorial followed all the steps including the github code as you mentioned. Able to start the Eureka Server. Producer, consumer micro services gets registered with the server successfully. But, I am unable to launch the accounts list page “http://localhost:8080/accountList” & even http://localhost:8080/ is not opening. It is throwing page not found error. Unable to find out the reason, if this is any web server issue or what. Could you please help me in this regard so that it would be helpful to me? Thanks.
Getting the below output, when I hit “http://localhost:8080/” instead of Accounts Web – Home page. Please let me know what could be causing the problem, it would be helpful to me.
{
“_links” : {
“profile” : {
“href” : “http://localhost:8080/profile”
}
}
}
Getting the below output, when I hit “http://localhost:8080/” instead of Accounts Web – Home page. Please let me know what could be causing the problem, it would be helpful to me.
{
“_links” : {
“profile” : {
“href” : “http://localhost:8080/profile”
}
}
}
Hi Dinesh Rajput,
Nice tutorial and Thanks for the details information covered for the architecture of micro services. I used the info provided and able to create micro services with discovery and registry both. But I am facing one problem always with this Eureka Server after few minutes of registering MS it is starting showing one warning message in Eureka Server stating
*******”EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.”********
Better if you can explore more on this. Thanks again for a Nice Tutorial.
Hi i am getting this error when runing discovery services
2019-04-14 19:36:21.663 WARN 860 — [ main] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization – cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘requestMappingHandlerMapping’ defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy
2019-04-14 19:36:21.665 INFO 860 — [ main] o.apache.catalina.core.StandardService : Stopping service Tomcat
2019-04-14 19:36:21.690 INFO 860 — [ main] utoConfigurationReportLoggingInitializer :
Error starting ApplicationContext. To display the auto-configuration report re-run your application with ‘debug’ enabled.
2019-04-14 19:36:21.703 ERROR 860 — [ main] o.s.boot.SpringApplication : Application startup failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘requestMappingHandlerMapping’ defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1589) ~[spring-beans-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:554) ~[spring-beans-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:759) ~[spring-beans-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866) ~[spring-context-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542) ~[spring-context-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.4.3.RELEASE.jar:1.4.3.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:761) [spring-boot-1.4.3.RELEASE.jar:1.4.3.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:371) [spring-boot-1.4.3.RELEASE.jar:1.4.3.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-1.4.3.RELEASE.jar:1.4.3.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1186) [spring-boot-1.4.3.RELEASE.jar:1.4.3.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1175) [spring-boot-1.4.3.RELEASE.jar:1.4.3.RELEASE]
at com.doj.discovery.DiscoveryMicroserviceServerApplication.main(DiscoveryMicroserviceServerApplication.java:12) [classes/:na]
Caused by: java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy
Hi Sir,
First of all, thanks for your valuable efforts into writing this article and providing a good walkthrough on the architecture. I would like to have the source code for the above example so as to get to know the real-time implementations of the concept. Kindly share me the git link for the source code.
Thanks,
Jegathesh.
what is the user name and pasword http://localhost:1111/login?
Hi Dinesh,
when i am using multiple microservice i am getting cannot find symbol by using RestTemplate with Eureka.
Hi Dinesh,
Please can you let me know how can I get the code snippets. Is CD provided with the book or code is uploaded on github