Microservices Using Spring Boot and Spring Cloud
Microservices is the hot buzzword in software development and many organizations prefer building their enterprise applications using microservices architecture. In the Java community, Spring Boot is the most widely used framework for building both monoliths and microservices. I am planning to write a series of articles covering how to build microservices using Spring Boot and Spring Cloud.
In this article, we are going to learn about the following:
- Monoliths
- What are microservices?
- Advantages of microservices
- Challenges with microservices
- Why Spring Boot and Spring Cloud are a good choice for microservices
- Introducing the application
Traditionally, we are building large enterprise applications in a modularized fashion (?!) but finally deploy them together as a single deployment unit (EAR or WAR). These are called monolithic applications.
There are some issues with the monolithic architecture, such as
- Large codebases become a mess over time.
- Multiple teams working on a single codebase becomes tedious.
- It is not possible to scale up only certain parts of the application.
- Technology updates/rewrites become complex and expensive tasks.
However, in my opinion, it is relatively easy to deploy and monitor monoliths compared to microservices.
A microservice is a service built around a specific business capability which can be independently deployed. So, to build large enterprise applications, we can identify the sub-domains of our main business domain and build each sub-domain as a microservice using Domain Driven Design (DDD) techniques. But in the end, we need to make all these microservices work together to serve the end user as if it is a single application.
Advantages of Microservices
- Comprehending a smaller codebase is easy.
- You can independently scale up highly used services.
- Each team can focus on one (or a few) microservice(s).
- Technology updates/rewrites become simpler.
Challenges With Microservices
- Getting the correct sub-domain boundaries, in the beginning, is hard.
- You need more skilled developers to handle distributed application complexities.
- Managing microservices-based applications without the proper DevOps culture is next to impossible.
- A local developer environment setup might become complex to test cross-service communications, though by using Docker/Kubernetes, this can be mitigated to some extent.
Spring Boot is the most popular and widely-used Java framework for building MicroServices. These days, many organizations prefer to deploy their applications in a Cloud environment instead of the headache of maintaining a datacenter themselves. But, we need to take good care of the various aspects to make our applications Cloud Native. There comes the beauty of Spring Cloud.
Spring Cloud is essentially an implementation of various design patterns to be followed while building Cloud Native applications. Instead of reinventing the wheel, we can simply take advantage of various Spring Cloud modules and focus on our main business problem rather than worrying about infrastructural concerns.
Following are just a few Spring Cloud modules that can be used to address distributed application concerns:
- Spring Cloud Config Server: Used to externalize the configuration of applications in a central config server with the ability to update the configuration values without requiring to restart the applications. We can use Spring Cloud Config Server with git, Consul, or ZooKeeper as a config repository.
- Service Registry and Discovery: As there could be many services and we need the ability to scale up or down dynamically, we need a Service Registry and Discovery mechanism so that service-to-service communication does not depend on hard-coded hostnames and port numbers. Spring Cloud provides Netflix Eureka-based Service Registry and Discovery support with just minimal configuration. We can also use Consulor ZooKeeper for Service Registry and Discovery.
- Circuit Breaker: In microservices-based architecture, one service might depend on another service, and if one service goes down, then failures may cascade to other services as well. Spring Cloud provides a Netflix Hystrix-based Circuit Breaker to handle these kinds of issues.
- Spring Cloud Data Streams: We may need to work with huge volumes of data streams using Kafka or Spark. Spring Cloud Data Streams provides higher-level abstractions to use those frameworks more easily.
- Spring Cloud Security: Some microservices need to be accessible to authenticated users only, and most likely, we'll want a Single Sign-On feature to propagate the authentication context across services. Spring Cloud Security provides authentication services using OAuth2.
- Distributed Tracing: One of the pain points with microservices is the ability to debug issues. One simple end-user action might trigger a chain of microservice calls; there should be a mechanism to trace the related call chains. We can use Spring Cloud Sleuth with Zipkin to trace cross-service invocations.
- Spring Cloud Contract: There is a high chance that separate teams will work on different microservices. There should be a mechanism for teams to agree upon API endpoint contracts so that each team can develop their APIs independently. Spring Cloud Contracthelps to create such contracts and validate them by both the service provider and consumer.
The code is developed using the Spring Boot Version 1.5.18.RELEASE. However you try the same with the 2.1.1.RELEASE too.
Shut down all the services, follow the below steps and then start the services:
- Create a configuration directory (say c:\configuration)
- Copy the configuration files (*.yml files from the zip) into this folder (c:\configuration)
- Open a git-bash shell and in the terminal, navigate to the folder i.e. cd /d c:\configuration. Run the below commands
o git init .
o git add .
o git commit -a -m "latest"
- Now, switch back to the config-server code and run the config server
- Then run the "discovery service" and during the startup, you should see a message stating that it is connecting to config-server and should locate the configuration for discovery server
- Then start the "edge service"
- Also, check the discovery-service.yml and see if the server.port is set to 8761. If not, set it to 8761 and start.
Note: Make sure to create the msa db in mysql
pc@DESKTOP-NQ639DU MINGW64 /c/configuration (master)
$ ls -ltr
total 6
-rw-r--r-- 1 pc 197121 23 Sep 20 2017 rating-service.yml
-rw-r--r-- 1 pc 197121 23 Sep 20 2017 product-service.yml
-rw-r--r-- 1 pc 197121 273 Sep 20 2017 edge-service.yml
-rw-r--r-- 1 pc 197121 23 Sep 20 2017 discovery-service.yml
-rw-r--r-- 1 pc 197121 23 Sep 20 2017 authorization-server.yml
-rw-r--r-- 1 pc 197121 520 Sep 20 2017 application.yml
config-server.java
ConfigServerApplication.java
@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
application.yml
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: file:///C:/configuration
server:
port: 8888
management:
security:
enabled: false
pom.xml
<?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.meetup.msa</groupId>
<artifactId>config-server</artifactId>
<packaging>jar</packaging>
<name>config-server</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>com.meetup.msa</groupId>
<artifactId>msa-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<!-- Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Cloud Config Server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!-- Undertow -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- MYSQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
---------------------------------------------------------------------------------------------------------------------
discovery-service
DiscoveryServiceApplication.java
@EnableEurekaServer
@SpringBootApplication
public class DiscoveryServiceApplication {
public static void main(String[] args) {
SpringApplication.run(DiscoveryServiceApplication.class, args);
}
}
application.yml
spring:
application:
name: discovery-service
cloud:
config:
uri: http://localhost:8888
pom.xml
<?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.meetup.msa</groupId>
<artifactId>discovery-service</artifactId>
<packaging>jar</packaging>
<name>discovery-service</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>com.meetup.msa</groupId>
<artifactId>msa-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<!-- Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Cloud Config -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- Eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
-------------------------
authorization-server
AuthorizationServerApplication.java
@SpringBootApplication
public class AuthorizationServerApplication implements CommandLineRunner {
private UserRepository userRepository;
@Autowired
public AuthorizationServerApplication(final UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public void run(final String... args) throws Exception {
// @formatter:off
final UserEntity user1 = new UserEntity()
.firstName("Chandra")
.lastName("V")
.email("cv@yopmail.com");
final UserEntity user2 = new UserEntity()
.firstName("Larry")
.lastName("Page")
.email("lp@yopmail.com");
final UserEntity user3 = new UserEntity()
.firstName("Sergey")
.lastName("Brin")
.email("sb@yopmail.com");
// @formatter:on
userRepository.save(Arrays.asList(user1, user2, user3));
}
public static void main(String[] args) {
SpringApplication.run(AuthorizationServerApplication.class, args);
}
}
Comments
Post a Comment