0% found this document useful (0 votes)
27 views

Microservices With Spring

Uploaded by

Prashant Kumar
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
27 views

Microservices With Spring

Uploaded by

Prashant Kumar
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 16

30/06/2020 Microservices with Spring

Spring Blog
All Posts  Engineering  Releases  News and Events 

Microservices with Spring


Introduction

NOTE: Revised July 2019

A simple example of setting up a microservices system using Spring, Spring Boot and Spring
Cloud.

Microservices allow large systems to be built up from a number of collaborating components.


It does at the process level what Spring has always done at the component level: loosely
coupled processes instead of loosely coupled components.

For example imagine an online shop


with separate microservices for user-
accounts, product-catalog order-
processing and shopping carts:

Inevitably there are a number of


moving parts that you have to setup
and con gure to build such a system.
How to get them working together is
not obvious - you need to have good
familiarity with Spring Boot since Spring Cloud leverages it heavily, several Net ix or other
OSS projects are required and, of course, there is some Spring con guration “magic”!

In this article I aim to clarify how things work by building the simplest possible system step-
by-step. Therefore, I will only implement a small part of the big system - the user account
service.

The Web-Application will make requests to the Account-Service microservice using a RESTful
API. We will also need to add a discovery service – so the other processes can nd each other.

https://spring.io/blog/2015/07/14/microservices-with-spring 1/16
30/06/2020 Microservices with Spring

The code for this application is here:

https://github.com/paulc4/microservices-demo.

The description of how it works is deliberately detailed. Impatient readers may prefer to
simply look at the code. Note that it contains three microservices in a single project.

Learn More
Sign up for SpringOne Platform 2019 – the premier conference for building scalable
microservice applications with Spring. This year we’re in Austin, TX from October 7th to
10th. Use the discount code S1P_Save200 to save money on your ticket. Need help
convincing your manager? Use this page.

Get the free eBook Migrating to Cloud-Native Architectures by Matt Stine

This webinar discusses tools and recipes to help you re-platform your monolithic apps
to modern cloud environments.

Updates (June 2018)


A number of changes since I originally wrote this blog:

1. A discussion of using multiple instances of the same service on the same host.. Demo
application updated to match.
2. A discussion of @LoadBalanced - how this works has changed since the Brixton release-
train (Spring Cloud 1.1.0.RELEASE).
3. Refactored con guration of Accounts microservice into its own class
AccountsConfiguration .
4. Upgraded to Spring Boot 2, so a few Boot classes have changed package.
5. Upgraded demo application to Spring Cloud Finchley release-train (including various
xes from the comments at the end - thanks for the feedback).
6. The Eureka server dependency has changed to
spring-cloud-starter-netflix-eureka-server .

https://spring.io/blog/2015/07/14/microservices-with-spring 2/16
30/06/2020 Microservices with Spring

Previous version, using Spring Boot 1.5.10 and Spring Cloud Edgeware SR3, is available as git
tag v1.2.0.

OK, let’s get started …

Service Registration

When you have multiple processes working together they need to nd each other. If you have
ever used Java’s RMI mechanism you may recall that it relied on a central registry so that RMI
processes could nd each other. Microservices has the same requirement.

The developers at Net ix had this problem when building their systems and created a
registration server called Eureka (“I have found it” in Greek). Fortunately for us, they made
their discovery server open-source and Spring has incorporated into Spring Cloud, making it
even easier to run up a Eureka server. Here is the complete discovery-server application:

@SpringBootApplication COPY
@EnableEurekaServer
public class ServiceRegistrationServer {

public static void main(String[] args) {


// Tell Boot to look for registration-server.yml
System.setProperty("spring.config.name", "registration-server");
SpringApplication.run(ServiceRegistrationServer.class, args);
}
}

It really is that simple!

Spring Cloud is built on Spring Boot and utilizes parent and starter POMs. The important parts
of the POM are:

<parent> COPY
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>

<dependencies>
<dependency>
<!-- Setup Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

https://spring.io/blog/2015/07/14/microservices-with-spring 3/16
30/06/2020 Microservices with Spring

<dependency>
<!-- Setup Spring MVC & REST, use Embedded Tomcat -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<!-- Spring Cloud starter -->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>

<dependency>
<!-- Eureka for service registration -->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
</dependencies>

<!-- Spring Cloud dependencies -->


<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

This POM has changed since I originally wrote the article to use Spring Boot as its parent not
Spring Cloud. Spring Cloud dependencies are provided via the dependency management
section.

An sample gradle build le is also included in the github code.

By default Spring Boot applications look for an Note: Finchley.RELEASE is the current "release
application.properties or application.yml train" - a set of co-ordinated releases -- see note
le for con guration. By setting the on Spring Cloud home page.

spring.config.name property we can tell Spring

Boot to look for a di erent le - useful if you have multiple Spring Boot applications in the
same project - as I will do shortly.

This application looks for registration-server.properties or registration-server.yml . Here


is the relevant con guration from registration-server.yml :

https://spring.io/blog/2015/07/14/microservices-with-spring 4/16
30/06/2020 Microservices with Spring

# Configure this Discovery Server COPY


eureka:
instance:
hostname: localhost
client: # Not a client, don't register with yourself (unless running
# multiple discovery servers for redundancy)
registerWithEureka: false
fetchRegistry: false

server:
port: 1111 # HTTP (Tomcat) port

By default Eureka runs on port 8761, but here we will use port 1111 instead. Also by
including the registration code in my process I might be a server or a client. The con guration
speci es that I am not a client and stops the server process trying to register with itself.

Try running the RegistrationServer now (see


below for help on running the application). You Using Consul
can open the Eureka dashboard here: Spring Cloud also supports Consul as an
http://localhost:1111 and the section showing alternative to Eureka. You start the Consul
Applications will be empty. Agent (its registration server) using a script and
then clients use it to nd their microservices.
From now on we will refer to the discovery-server For details, see this blog article or project home
since it could be Eureka or Consul (see side page.

panel).

Creating a Microservice: Account-Service

A microservice is a stand-alone process that handles a well-de ned requirement.

When con guring applications with


Spring we emphasize Loose Coupling
and Tight Cohesion, These are not
new concepts (Larry Constantine is
credited with rst de ning these in
the late 1960s - reference) but now
we are applying them, not to
interacting components (Spring Beans), but to interacting processes.

In this example, I have a simple Account management microservice that uses Spring Data to
implement a JPA AccountRepository and Spring REST to provide a RESTful interface to
account information. In most respects this is a straightforward Spring Boot application.
https://spring.io/blog/2015/07/14/microservices-with-spring 5/16
30/06/2020 Microservices with Spring

What makes it special is that it registers itself with the discovery-server at start-up. Here is the
Spring Boot startup class:

@EnableAutoConfiguration COPY
@EnableDiscoveryClient
@Import(AccountsWebApplication.class)
public class AccountsServer {

@Autowired
AccountRepository accountRepository;

public static void main(String[] args) {


// Will configure using accounts-server.yml
System.setProperty("spring.config.name", "accounts-server");

SpringApplication.run(AccountsServer.class, args);
}
}

The annotations do the work:

1. @EnableAutoConfiguration - de nes this as a Spring Boot application.


2. @EnableDiscoveryClient - this enables service registration and discovery. In this case,
this process registers itself with the discovery-server service using its application name
(see below).
3. @Import(AccountsWebApplication.class) - this Java Con guration class sets up
everything else (see below for more details).

What makes this a microservice is the registration with the discovery-server via
@EnableDiscoveryClient and its YML con guration completes the setup:

# Spring properties COPY


spring:
application:
name: accounts-service

# Discovery Server Access


eureka:
client:
serviceUrl:
defaultZone: http://localhost:1111/eureka/

# HTTP Server
server:
port: 2222 # HTTP (Tomcat) port

Note that this le

https://spring.io/blog/2015/07/14/microservices-with-spring 6/16
30/06/2020 Microservices with Spring

1. Sets the application name as accounts-service . This service registers under this name
and can also be accessed by this name - see below.
2. Speci es a custom port to listen on (2222). All my processes are using Tomcat, they can’t
all listen on port 8080.
3. The URL of the Eureka Service process - from the previous section.

Run the AccountsService


application now and let it nish
initializing. Refresh the
dashboard
http://localhost:1111 and you
should see the ACCOUNTS-
SERVICE listed under
Applications. Registration takes
up to 30 seconds (by default)
so be patient - check the log
output from RegistrationService

For more detail, go here: Warning: Do not try to display XML output
http://localhost:1111/eureka/apps/ and you using the internal web-viewer of Eclipse/STS
should see something like this: because it cannot do so. Use your favorite web
browser instead.
<applications> COPY

<versions__delta>1</versions__delta>
<apps__hashcode>UP_1_</apps__hashcode>
<application>
<name>ACCOUNTS-SERVICE</name>
<instance>

<hostName>autgchapmp1m1.corp.emc.com</hostNa
me>
<app>ACCOUNTS-SERVICE</app>
<ipAddr>172.16.84.1</ipAddr>
<status>UP</status>

<overriddenstatus>UNKNOWN</overriddenstatus>
<port enabled="true">3344</port>
<securePort
enabled="false">443</securePort>
...
</instance>
</application>
</applications>

https://spring.io/blog/2015/07/14/microservices-with-spring 7/16
30/06/2020 Microservices with Spring

Alternatively go to http://localhost:1111/eureka/apps/ACCOUNTS-SERVICE and see just the


details for AccountsService - if it’s not registered you will get a 404.

Configuration Options
Registration Time: Registration takes up to 30s because that is the default client refresh
time. You can change this by setting the eureka.instance.leaseRenewalIntervalInSeconds
property to a smaller number (in the demo application I have set it to 5). This is not
recommended in production. See also.

eureka: COPY

instance:
leaseRenewalIntervalInSeconds: 5 # DO NOT DO THIS IN PRODUCTION

Registration Id: A process (microservice) registers with the discovery-service using a unique
id. If another process registers with the same id, it is treated as a restart (for example some
sort of failover or recovery) and the rst process registration is discarded. This gives us the
fault-tolerant system we desire.

To run multiple instances of the same process (for load-balancing and resilience) they need to
register with a unique id. When I rst wrote this blog, that was automatic and since the Brixton
release-train, it is again.

Under the Angel release train, the instance-id, used by a client to register with a discovery
server, was derived from the client’s service name (the same as the Spring application name)
and also the client’s host name. The same processes running on the same host would
therefore have the same id, so only one could ever register.

Fortunately you could set the id property manually via the client’s Eureka metadata map, like
this:

eureka: COPY

instance:
metadataMap:
instanceId:
${spring.application.name}:${spring.application.instance_id:${server.port}}

Since the Brixton release train, this is now the default. So what does it do?

We are setting the instanceId to application-name:instance_id , but if instance_id is not


de ned, we will use application-name::server-port instead. Note that the
https://spring.io/blog/2015/07/14/microservices-with-spring 8/16
30/06/2020 Microservices with Spring

spring.application.instance_id is only set when using Cloud Foundry but it conveniently


provides a unique id number for each instance of the same application. We can do something
similar when running elsewhere by using the server-port (since di erent instances on the
same machine must listen on di erent ports. Another example you will often see is
${spring.application.name}:${spring.application.instance_id:${random.value}} but I

personally nd using the port number makes each instance easy to identify - the random
values are just long strings that don’t mean anything.

Note: The syntax ${x:${y}} is Spring property shorthand for ${x} != null ? ${x} : ${y} .

Since the Brixton release there is also a dedicated property for this:

eureka: COPY

instance:
instanceId:
${spring.application.name}:${spring.application.instance_id:${random.value}}

Accessing the Microservice: Web-Service

To consume a RESTful service, Spring provides the RestTemplate class. This allows you to
send HTTP requests to a RESTful server and fetch data in a number of formats - such as JSON
and XML.

Which formats can be used depends on the Note: The Accounts microservice provides a RESTful
presence of marshaling classes on the interface over HTTP, but any suitable protocol could
classpath - for example JAXB is always be used. Messaging using AMQP or JMS is an obvious

detected since it is a standard part of Java. alternative (in which case the Discovery Server is no
longer needed - instead processes need to know the
JSON is supported if Jackson jars are
names of the queues to talk to, consider using the
present in the classpath.
Spring Cloud Con guration Server for this).

A microservice (discovery) client can use a RestTemplate and Spring will automatically
con gure it to be microservice aware (more of this in a moment).

Encapsulating Microservice Access


Here is part of the WebAccountService for my client application:

@Service COPY

public class WebAccountsService {

@Autowired // NO LONGER auto-created by Spring Cloud (see below)

https://spring.io/blog/2015/07/14/microservices-with-spring 9/16
30/06/2020 Microservices with Spring

@LoadBalanced // Explicitly request the load-balanced template


// with Ribbon built-in
protected RestTemplate restTemplate;

protected String serviceUrl;

public WebAccountsService(String serviceUrl) {


this.serviceUrl = serviceUrl.startsWith("http") ?
serviceUrl : "http://" + serviceUrl;
}

public Account getByNumber(String accountNumber) {


Account account = restTemplate.getForObject(serviceUrl
+ "/accounts/{number}", Account.class, accountNumber);

if (account == null)
throw new AccountNotFoundException(accountNumber);
else
return account;
}
...
}

Note that my WebAccountService is just a wrapper for the RestTemplate fetching data from
the microservice. The interesting parts are the serviceUrl and the RestTemplate .

Accessing the Microservice


As shown below, the serviceUrl is provided by the main program to the
WebAccountController (which in turn passes it to the WebAccountService ):

@SpringBootApplication COPY

@EnableDiscoveryClient
@ComponentScan(useDefaultFilters=false) // Disable component scanner
public class WebServer {

// Case insensitive: could also use: http://accounts-service


public static final String ACCOUNTS_SERVICE_URL
= "http://ACCOUNTS-SERVICE";

public static void main(String[] args) {


// Will configure using web-server.yml
System.setProperty("spring.config.name", "web-server");
SpringApplication.run(WebServer.class, args);
}

@LoadBalanced // Make sure to create the load-balanced template


@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}

https://spring.io/blog/2015/07/14/microservices-with-spring 10/16
30/06/2020 Microservices with Spring

/**
* Account service calls microservice internally using provided URL.
*/
@Bean
public WebAccountsService accountsService() {
return new WebAccountsService(ACCOUNTS_SERVICE_URL);
}

@Bean
public WebAccountsController accountsController() {
return new WebAccountsController
(accountsService()); // plug in account-service
}
}

A few points to note:

1. The WebController is a typical Spring MVC view-based controller returning HTML. The
application uses Thymeleaf as the view-technology (for generating dynamic HTML)
2. WebServer is also a @EnableDiscoveryClient but in this case as well as registering itself
with the discovery-server (which is not necessary since it o ers no services of its own) it
uses Eureka to locate the account service.
3. The default component-scanner setup inherited from Spring Boot looks for @Component
classes and, in this case, nds my WebAccountController and tries to create it. However,
I want to create it myself, so I disable the scanner like this
@ComponentScan(useDefaultFilters=false) .
4. The service-url I am passing to the WebAccountController is the name the service used to
register itself with the discovery-server - by default this is the same as the
spring.application.name for the process which is account-service - see
account-service.yml above. The use of upper-case is not required but it does help
emphasize that ACCOUNTS-SERVICE is a logical host (that will be obtained via discovery)
not an actual host.

Load Balanced RestTemplate


The RestTemplate bean will be intercepted and auto-con gured by Spring Cloud (due to the
@LoadBalanced annotation) to use a custom HttpRequestClient that uses Net ix Ribbon to
do the microservice lookup. Ribbon is also a load-balancer so if you have multiple instances of
a service available, it picks one for you. (Neither Eureka nor Consul on their own perform
load-balancing so we use Ribbon to do it instead).

Note: From the Brixton Release Train (Spring Cloud 1.1.0.RELEASE), the RestTemplate is no
longer created automatically. Originally it was created for you, which caused confusion and
potential con icts (sometimes Spring can be too helpful!).

https://spring.io/blog/2015/07/14/microservices-with-spring 11/16
30/06/2020 Microservices with Spring

Note that this instance is quali ed using @LoadBalanced . (The annotation is itself annotated
with @Qualifier - see here for details). Thus if you have more than one RestTemplate bean,
you can make sure to inject the right one, like this:

@Autowired COPY
@LoadBalanced // Make sure to inject the load-balanced template
protected RestTemplate restTemplate;

If you look in the RibbonClientHttpRequestFactory you will see this code:

String serviceId = originalUri.getHost(); COPY

ServiceInstance instance =
loadBalancer.choose(serviceId); // loadBalancer uses Ribbon
... if instance non-null (service exists) ...
URI uri = loadBalancer.reconstructURI(instance, originalUri);

The loadBalancer takes the logical service-name (as registered with the discovery-server) and
converts it to the actual hostname of the chosen microservice.

A RestTemplate instance is thread-safe and can be used to access any number of services in
di erent parts of your application (for example, I might have a CustomerService wrapping the
same RestTemplate instance accessing a customer data microservice).

Configuration
Below the relevant con guration from web-server.yml . It is used to:

1. Set the application name


2. De ne the URL for accessing the discovery server
3. Set the Tomcat port to 3333

# Spring Properties COPY

spring:
application:
name: web-service

# Discovery Server Access


eureka:
client:
serviceUrl:
defaultZone: http://localhost:1111/eureka/

# HTTP Server
server:
port: 3333 # HTTP (Tomcat) port

https://spring.io/blog/2015/07/14/microservices-with-spring 12/16
30/06/2020 Microservices with Spring

How to Run the Demo

A small demo of this system is at http://github.com/paulc4/microservices-demo. Clone it and


either load into your favorite IDE or use maven directly. Suggestions on how to run the demo
are included in the README on the project homepage.

Extra Notes

Some notes about Spring Boot usage by these applications. If you are not familiar with Spring
Boot, this explains some of the “magic”!

View Templating Engines


The Eureka dashboard (inside RegistrationServer ) is implemented using FreeMarker
templates but the other two applications use Thymeleaf. To make sure each uses the right
view engine, there is extra con guration in each YML le.

This is at the end of registration-server.yml to disable Thymeleaf.

... COPY

# Discovery Server Dashboard uses FreeMarker. Don't want Thymeleaf templates


spring:
thymeleaf:
enabled: false # Disable Thymeleaf spring:

Since both AccountService and WebService use thymeleaf, we also need to point each at
their own templates. Here is part of account-server.yml :

# Spring properties COPY

spring:
application:
name: accounts-service # Service registers under this name
freemarker:
enabled: false # Ignore Eureka dashboard FreeMarker templates
thymeleaf:
cache: false # Allow Thymeleaf templates to be reloaded at runtime
prefix: classpath:/accounts-server/templates/
# Template location for this application only
...

web-server.yml is similar but its templates are de ned by

prefix: classpath:/web-server/templates/ COPY

https://spring.io/blog/2015/07/14/microservices-with-spring 13/16
30/06/2020 Microservices with Spring

Note the / on the end of each spring.thymeleaf.prefix classpath - this is crucial.

Command-Line Execution
The jar is compiled to automatically run io.pivotal.microservices.services.Main when
invoked from the command-line - see Main.java.

The Spring Boot option to set the start-class can be seen in the POM:

<properties> COPY

<!-- Stand-alone RESTFul application for testing only -->


<start-class>io.pivotal.microservices.services.Main</start-class>
</properties>

AccountsConfiguration class

@SpringBootApplication COPY

@EntityScan("io.pivotal.microservices.accounts")
@EnableJpaRepositories("io.pivotal.microservices.accounts")
@PropertySource("classpath:db-config.properties")
public class AccountsWebApplication {
...
}

This is the main con guration class for AccountService which is a classic Spring Boot
application using Spring Data. The annotations do most of the work:

1. @SpringBootApplication - de nes this as a Spring Boot application. This convenient


annotation combines @EnableAutoConfiguration , @Configuration and @ComponentScan
(which, by default, causes Spring to search the package containing this class, and its sub-
packages, for components - potential Spring Beans: AccountController and
AccountRepository ) .
2. @EntityScan("io.pivotal.microservices.accounts") - because I am using JPA, I need to
specify where the @Entity classes are. Normally this is an option you specify in JPA’s
persistence.xml or when creating a LocalContainerEntityManagerFactoryBean . Spring
Boot will create this factory-bean for me because the spring-boot-starter-data-jpa
dependency is on the class path. So an alternative way of specifying where to nd the
@Entity classes is by using @EntityScan . This will nd Account .
3. @EnableJpaRepositories("io.pivotal.microservices.accounts") - look for classes
extending Spring Data’s Repository marker interface and automatically implement
them using JPA - see Spring Data JPA.
4. @PropertySource("classpath:db-config.properties") - properties to con gure my
DataSource – see db-con g.properties.

https://spring.io/blog/2015/07/14/microservices-with-spring 14/16
30/06/2020 Microservices with Spring

Configuring Properties
As mentioned above, Spring Boot applications look for either application.properties or
application.yml to con gure themselves. Since all three servers used in this application are

in the same project, they would automatically use the same con guration.

To avoid that, each speci es an alternative le by setting the spring.config.name property.

For example here is part of WebServer.java .

public static void main(String[] args) { COPY

// Tell server to look for web-server.properties or web-server.yml


System.setProperty("spring.config.name", "web-server");
SpringApplication.run(WebServer.class, args);
}

At runtime, the application will nd and use web-server.yml in src/main/resources .

Logging
Spring Boot sets up INFO level logging for Spring by default. Since we need to examine the
logs for evidence of our microservices working, I have raised the level to WARN to reduce the
amount of logging.

To do this, the logging level would need to be speci ed in each of the xxxx-server.yml
con guration les. This is usually the best place to de ne them as logging properties cannot
be speci ed in property les (logging has already been initialized before @PropertySource
directives are processed). There is a note on this in the Spring Boot manual, but it’s easy to
miss.

Rather than duplicate the logging con guration in each YAML le, I instead opted to put it in
the logback con guration le, since Spring Boot uses logback - see
src/main/resources/logback.xml. All three services will share the same logback.xml .

https://spring.io/blog/2015/07/14/microservices-with-spring 15/16
30/06/2020 Microservices with Spring

169 Comments spring.io 🔒 


1 Login

 Recommend 45 t Tweet f Share Sort by Best

Join the discussion…

LOG IN WITH

OR SIGN UP WITH DISQUS ?

Name

mslcdiscuss • 3 years ago


Is there a standard way documented somewhere on how to
implement CQRS within the demo project that is explained
above.
50 △ ▽ 1 • Reply • Share ›

https://spring.io/blog/2015/07/14/microservices-with-spring 16/16

You might also like