Microservices With Spring
Microservices With Spring
Spring Blog
All Posts Engineering Releases News and Events
A simple example of setting up a microservices system using Spring, Spring Boot and Spring
Cloud.
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
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.
This webinar discusses tools and recipes to help you re-platform your monolithic apps
to modern cloud environments.
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.
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 {
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>
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.
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.
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.
https://spring.io/blog/2015/07/14/microservices-with-spring 4/16
30/06/2020 Microservices with Spring
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.
panel).
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;
SpringApplication.run(AccountsServer.class, args);
}
}
What makes this a microservice is the registration with the discovery-server via
@EnableDiscoveryClient and its YML con guration completes the setup:
# HTTP Server
server:
port: 2222 # HTTP (Tomcat) port
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.
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
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?
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}}
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).
@Service COPY
https://spring.io/blog/2015/07/14/microservices-with-spring 9/16
30/06/2020 Microservices with Spring
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 .
@SpringBootApplication COPY
@EnableDiscoveryClient
@ComponentScan(useDefaultFilters=false) // Disable component scanner
public class WebServer {
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
}
}
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.
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;
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:
spring:
application:
name: web-service
# 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
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”!
... COPY
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:
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
...
https://spring.io/blog/2015/07/14/microservices-with-spring 13/16
30/06/2020 Microservices with Spring
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
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:
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.
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
LOG IN WITH
Name
https://spring.io/blog/2015/07/14/microservices-with-spring 16/16