Getting started with microservices using SpringBot
Microservices are components developed using the microservice architectural style, where each service follows a single responsibility principle.
A micoservice architecture is often compared and contrasted against the traditional monolithic achitectural style, where all application or system logic exists as part of a single application.
There are benefits to both approaches and choosing which one is right for you will depend on your unique circumstances.
Benefits of micoservices.
- Testable - Being able to test each service in isolation makes finding issues easier
- Scalable - Not all services are created equal, some services may require more compute resources to perform their task. Within a microservice architecture, each service can be independently scaled.
- Ownership - Each service can be owned and maintained by a different team
- Flexibility - Each service can be developed, maintained, and released independently allowing for faster and more reliable releases and updates. Each service can be significantly less complex than the whole, heavily mitigating the risks associated with complex changes.
Draw-backs of microservices
- More complex deployments - While this issue is becoming less relevant with the more prevalent use of tools such as kubernetes, a system using microservices can be more complex due to the additional moving parts.
- Latency - While performance can be improved with a microservice achitecture, by adding more connections and hops for each request, we add latency to our system.
Microservices with SpringBot
SpringBot has many features that make it appropriate for use within a microservice architecture. Additionally, being built using Spring Boot, SpringBot also supports the addition of many other features.
API.
Having an effective API is fundamental building block of developing a microservice architecture.
SpringBot provides both a REST API [TODO] and a GraphQL API for this purpose.
Consuming a RESTful web service.
Providing an API to be consumed is incredibly important in integrating your service into a microservice achitecture. It is also incredibly important to be able to consume data from an API provided by another service.
Rest Template
SpringBoot provides a mechanism for querying APIs out of the box. This mechanism is the RestTemplate
.
To make use of the RestTemplate
-
Ensure one is declared within in your application context.
@Bean public RestTemplate restTemplate(RestTemplateBuilder builder) { return builder.build(); }
-
Inject it into the class where you wish to use it.
@Autowired private RestTemplate restTemplate;
We recommend constructor injection where possible.
-
Utilise your
restTemplate
. For example to fetch a list of articles from another service.final String endpoint = "http://localhost:8080/api/article"; var articles = restTemplate.getForObject(endpoint, ArticlePojo[].class);
This uses a simple POJO class as seen below:
package com.springbot.basic.pojos; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; @Data // We add this to ensure we discard anything properties that we have not declared here @JsonIgnoreProperties(ignoreUnknown = true) public class ArticlePojo { private String title; private String summary; private String content; private Boolean featured; }
Authentication and authorisation.
Each service must be able to correctly authenticate against each other in a secure manner such that each request is authorised. This is important to ensure that malicious third parties cannot gain access to our system, while also ensuring that our services are not interrupted by authentication issues.
Keeping with the principles of our microservice architecture, it is recommended that an external authentication provider be used to ensure we maintain holistic control over our services security. This can be supplied within our own architecture or a third party solution such as Auth0.
For details on how to use Auth0 in your SpringBot application please see the Spring Security OAuth client documentation.
To use the built in authentication service provided, an authentication token will need to be requested and presented for each request.
Using RestTemplate
s we can achieve this by adding cookies to all requests.
-
Logging in.
private List<String> login() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); var map = new LinkedMultiValueMap<String, String>(); // IMPORTANT: Ensure that the scope of this user is limited as much as possible map.add("username", "user@example.com"); // This password should never be hardcoded but should be stored encrypted to minimise risk map.add("password", getEncryptedPassword("user@example.com")); var request = new HttpEntity<MultiValueMap<String, String>>(map, headers); ResponseEntity<String> response = restTemplate.postForEntity("http://localhost:8080/auth/login", request, String.class); return response.getHeaders().get("Set-Cookie"); }
-
Add login token and CSRF tokens to request
var cookies = this.login(); HttpHeaders headers = new HttpHeaders(); cookies.forEach(cookie -> headers.add("Cookie", cookie)); final String endpoint = "http://localhost:8080/api/article"; return new ResponseEntity<>(restTemplate.getForObject(endpoint, ArticlePojo[].class, new HttpEntity<String>(headers)), HttpStatus.OK);
Using the built in authentication you will need to handle the token expiry and renewal.
Configuration and service discovery.
In the examples above, the base URL of the remote service has been hard coded. This is not ideal as it makes changing the base URL of the remote service difficult, especially when used in different environments.
There are different methods of locating different services, ranging from configuration files all the way to service discovery tools such as Netflix Eureka (see the Microservices with Spring blog post for some implementation details).
The simplest method is making use of the SpringBot application profiles and configuration to load the base URLs for each service per environment.
Caching.
Caching is important to mitigate the additional latency added by the additional request hops. Whilst caching is available as part of the application (see SpringBoot caching), it is recommended that caching be performed as part of the hosting infrastructure.
Spring Cloud.
So far we have explored using SpringBot within a simple microservice architecture. Java Spring is often considered to be the defacto standard for Java microservices there exists a large range of features that could be leveraged. King among these is Spring Cloud which is a suite of Spring projects that supply many of the tools required to deploy a complete and efficient collection of microservices.
Was this article helpful?