Step By Step Implementation Of Microservices with Spring Boot – Sample Code Provided
We have discussed the Microservices concepts like What are Microservices? Why use it? When to use it? in our previous article ” An Introduction to Microservices Architecture”
In this article, we will discuss the pros/cons of microservices so that you can make a better decision and after that, we will see how to implement microservices with Spring Boot.
So be with us to learn that is the Future!!
Hardware has chased down applications but it is not getting better any more in comparison to internet traffic which is huge and unpredictable. So, there should be a change in architecture and web interface to handle such compatibility
Thus we have an architecture along with many other supporting technologies to tackles this and accept now monolithic applications are nearly gone.
Everything has its pros and cons in all aspect so here we will also discuss the same about Microservices.
Pros:
- You can have heterogeneous and latest types of technology stacks.
- A bulkhead application can be handled efficiently and its implantation is not cascaded so that if one system fails others can live resiliently.
- A huge and dynamic application will be scalable
- An application will be composed. Release cycles will not be costly.
- An application will be a group of isolated systems and deployment will not be overheard.
- Organized implementation helps to use human and technical resources efficiently.
Cons:
- It is very expensive for small applications; the initial cost is very high.
- Application and deployment will be distributed so integration and testing effort could be high.
- Sometimes developer complains about the duplication of efforts.
- Increasing service APIs could be very complex to refactor. Memory consumption could be high
Just quoting from Martin Fowler:
One reasonable argument we’ve heard is that you shouldn’t start with a microservices architecture. Instead begin with a monolith, keep it modular, and split it into microservices once the monolith becomes a problem
So notably it’s good if you are starting, go with the monolith and keep it modular later if application grows to huge and complex then move to the Microservices as it is very expensive in terms of technology, efforts, and level of architecture design.
Further here we will create a project to show demo for this. Microservices is an architectural style whose implementation is supported by many frameworks i.e. Dropwizard, Vertx, Spring Boot, Restlet, Spark + Unirest (REST client, Spark doesn’t provide a REST client itself), etc.
Over here to show the demo we will use Spring boot. This is the most popular framework for microservices as we know it is powered by Spring.
Implementation Of Microservices with Spring Boot
In this project, we will use Eureka server which is nothing but a service discovery pattern implementation. In this, every microservice is registered and a client looks up the Eureka server to access dependent microservice to complete the job.
We are trying to mimic the real world scenario here, wherein Eureka Server and different microservices are hosted separately.
Initialize Eureka Server
For our demo purpose, we are simply using Eureka as our service registration server. For that, you just need to use correct dependencies and specify Eureka properties in your application’s yaml or properties file.
Eureka Server POM
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
<?xml version="1.0" encoding="UTF-8"?> <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"> <modelVersion>4.0.0</modelVersion> <groupId>com.opencodez.microservice</groupId> <artifactId>spring-discovery-server</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>spring-discovery-server</name> <description>Demo project for Microservices with Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.2.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Finchley.BUILD-SNAPSHOT</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </repository> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> </project> |
application.yaml
Below is the main configuration that will make your application as Eureka Server
1 2 3 4 5 6 7 8 9 |
server: port: ${PORT:8761} # Indicate the default PORT where this service will be started eureka: client: registerWithEureka: false #telling the server not to register himself in the service registry fetchRegistry: false server: waitTimeInMsWhenSyncEmpty: 0 #wait time for subsequent sync |
Once we start our application, the Eureka Server will display details about all services registered and available to use.
At this moment, we don’t have any service registered hence you see the warning in red.
Microservices Clients
We will define two simple projects as Employee Service and Employer Service. These will register with Eureka Server and become available. The core of these projects would be its application properties, in which they will define the name and other parameters with which they will register with the server.
Employee Service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
server: port: 8098 #default port where the service will be started eureka: #tells about the Eureka server details and its refresh time instance: leaseRenewalIntervalInSeconds: 1 leaseExpirationDurationInSeconds: 2 client: serviceUrl: defaultZone: http://127.0.0.1:8761/eureka/ healthcheck: enabled: true lease: duration: 5 spring: application: name: employee-service #current service name to be used by the eureka server |
Employer Service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
server: port: 9098 #port number eureka: instance: leaseRenewalIntervalInSeconds: 1 leaseExpirationDurationInSeconds: 2 client: serviceUrl: defaultZone: http://127.0.0.1:8761/eureka/ healthcheck: enabled: true lease: duration: 5 spring: application: name: employer-service #service name logging: level: com.opencodez.microservice: DEBUG |
Once we start both the client project, they will get registered with Eureka.
Note that the red warning has gone.
Using the Published Microservice
Both the client has registered themselves with distinct names. These names will be used to find the service in other clients. In our example, the EMPLOYEE-SERVICE returns static data. This data is fetched in EMPLOYER SERVICE and displayed.
EMPLOYEE-SERVICE
1 2 3 4 5 6 7 8 9 10 11 |
@RequestMapping(value = "/getEmployeeDetail/" , method = RequestMethod.GET) public Employee getEmployeeDetail(@RequestParam("id") int id) { System.out.println("Getting employee detail..."); List<Employee> list = new ArrayList<Employee>(); //sample data list.add(new Employee(1, "Alex")); list.add(new Employee(2, "Robin")); return list.get(id-1); } |
We have only 2 predefined data set, we will return from this set only.
EMPLOYER SERVICE
1 2 3 4 5 6 7 8 9 10 11 12 13 |
private static String SERVICE = "http://EMPLOYEE-SERVICE/getEmployeeDetail/?id="; @RequestMapping(value = "/getEmployeeDetailForEmployer/{empID}", method = RequestMethod.GET) public String getEmployeeDetailForEmployer(@PathVariable int empID) { String response = restTemplate.exchange(SERVICE + empID, HttpMethod.GET, null, new ParameterizedTypeReference<String>() { }).getBody(); System.out.println("Response Received as " + response); return "Employee id - " + empID + " \n Employee Details " + response; } |
Note how the employer service is accessing employee service. It doesn’t have any host or port. Based on only service name, it managed to locate and use the service.
OutputConclusion
Here we have seen the probably tiniest implementation of microservices based on Spring boot. Here services are very isolated to the server configuration and deployment.
You can download complete code from out GitHub Repository
Download Code