Welcome to the Angular with Spring Cloud Microservices tutorial series. In our previous Angular + Spring Boot Fullstack Application Development Tutorial Series, we have implemented the following so far.
Creating Backend – Spring REST API – Part 1
Creating Backend – Spring REST API – Part 2
Creating Angular 10 Client Application – Part 3
Secure Spring Boot Angular Application with Two Factor Authentication
Dockerize Angular with NGINX and Spring Boot with MySQL using Docker Compose
Deploy Angular, Spring Boot, and MySQL Application to DigitalOcean Kubernetes in 30 mins
Integrate Razorpay Payment Gateway with Angular and Spring Boot Application in 14 Simple Steps
How to Write Junit 5 Test Cases for Spring REST Controller using Mockito
How to Implement Spring Boot Angular User Registration Email Verification
Build a CRUD application with Angular and Spring Boot in 15 Steps
Implement Server-side Pagination with Angular and Spring Boot in 3 Steps
Using Angular Material Datepicker with Custom Date Format
Create Reusable Angular Confirmation Dialog
Introduction
In this series, we are going to decompose our monolith backend application into microservices using Spring Cloud. Before we dive deep, let’s see what are microservices and what Spring Cloud provides to develop them.
What are Microservices?
Microservices are an architectural style in which a single application comprises many loosely coupled and independently deployable smaller services.
What is Spring Cloud?
The distributed nature of microservices brings challenges. Spring Cloud helps you mitigate these with several ready-to-run cloud patterns. It can help with service discovery, load-balancing, circuit-breaking, distributed tracing, and monitoring. It can even act as an API gateway.
In this series, we are gonna implement some of the common Microservices patterns like API Gateway Pattern, Circuit Breaker Pattern, Service Discovery Pattern, and External Configuration using Spring API Cloud Gateway, Resilience4j, Netflix Eureka, and Spring Cloud Config respectively.
What you’ll build
Our Spring Boot Backend application consists of the following REST APIs:
- User Service
- Authentication Service
- Product Service
- Order Service
Now, we are gonna do the following
- Decompose User & Authentication service as a single microservice since both of these connect to the same database. Product and Order service will be decomposed into 2 different microservices. It is recommended that each microservice should,
- Follow the Single Responsibility Principle in which a microservice should have only one responsibility.
- Have its own database since it should be independent. So that, when one goes down, it will not affect the other microservices.
- Implement Spring API Cloud Gateway which will act as a single point of entry to external requests. This will take care of authentication and fault tolerance using Resilience4j which is one of the supported implementations of Spring Cloud Circuit Breaker.
- Implement a Discovery Service using Spring Cloud Netflix Eureka server. Service discovery allows services to find and communicate with each other without hard-coding the hostname and port. Each service has to register with the service registry. So that, microservices can communicate with other microservices with just the instance name of the service using Service Discovery Client.
- Implement a Config Service which acts as a central place to manage external properties for applications across all environments. Spring Cloud Config provides server-side and client-side support for externalized configuration in a distributed system. So we are gonna use this to store the configurations in a remote git repository and serve them to the microservices.
Project Structure
What you’ll need
- Spring Tool Suite 4 or any other IDE of your choice
- JDK 11
- MySQL Server 8
- node.js
Tech Stack
- Spring Boot 2, Spring Security 5, and Spring Cloud 2021.0.1
- Spring Data JPA and Hibernate 5
- Angular 13 and Bootstrap 4
Design
Create Spring Cloud Parent Project
Firstly, let’s create a spring cloud parent project which will include all the other modules as a child.
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.javachinna</groupId>
<artifactId>spring-social-login-cloud-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-social-login-cloud-demo</name>
<description>Demo project for Spring Boot</description>
<packaging>pom</packaging>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2021.0.1</spring-cloud.version>
</properties>
<modules>
<module>config-service</module>
<module>discovery-service</module>
<module>gateway-service</module>
<module>user-auth-service</module>
<module>product-service</module>
<module>order-service</module>
</modules>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</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>
</project>
Decompose Monolithic Spring Boot Backend application
Secondly, let’s decompose the Spring Boot backend application into an independent microservice per responsibility.
Existing Project Structure
+---pom.xml
|
+---src
| \---main
| +---java
| | \---com
| | \---javachinna
| | | DemoApplication.java
| | |
| | +---config
| | | WebConfig.java
| | | AppProperties.java
| | | CurrentUser.java
| | | RestAuthenticationEntryPoint.java
| | | SetupDataLoader.java
| | | WebSecurityConfig.java
| | |
| | +---controller
| | | AuthController.java
| | | UserController.java
| | |
| | +---dto
| | | ApiResponse.java
| | | JwtAuthenticationResponse.java
| | | LocalUser.java
| | | LoginRequest.java
| | | SignUpRequest.java
| | | SocialProvider.java
| | | UserInfo.java
| | |
| | +---exception
| | | | BadRequestException.java
| | | | OAuth2AuthenticationProcessingException.java
| | | | ResourceNotFoundException.java
| | | | UserAlreadyExistAuthenticationException.java
| | | |
| | | \---handler
| | | RestResponseEntityExceptionHandler.java
| | |
| | +---model
| | | Role.java
| | | User.java
| | |
| | +---repo
| | | RoleRepository.java
| | | UserRepository.java
| | |
| | +---security
| | | +---jwt
| | | | TokenAuthenticationFilter.java
| | | | TokenProvider.java
| | | |
| | | \---oauth2
| | | | CustomOAuth2UserService.java
| | | | CustomOidcUserService.java
| | | | HttpCookieOAuth2AuthorizationRequestRepository.java
| | | | OAuth2AccessTokenResponseConverterWithDefaults.java
| | | | OAuth2AuthenticationFailureHandler.java
| | | | OAuth2AuthenticationSuccessHandler.java
| | | |
| | | \---user
| | | FacebookOAuth2UserInfo.java
| | | GithubOAuth2UserInfo.java
| | | GoogleOAuth2UserInfo.java
| | | LinkedinOAuth2UserInfo.java
| | | OAuth2UserInfo.java
| | | OAuth2UserInfoFactory.java
| | |
| | +---service
| | | LocalUserDetailService.java
| | | UserService.java
| | | UserServiceImpl.java
| | |
| | +---util
| | | CookieUtils.java
| | | GeneralUtils.java
| | |
| | \---validator
| | PasswordMatches.java
| | PasswordMatchesValidator.java
| |
| \---resources
| application.properties
| messages_en.properties
User Auth Service
Thirdly, let’s create a new maven project user-auth-service
and move the UserController
, AuthController
and all of its relevant code to this project.
Project Dependencies
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.javachinna</groupId>
<artifactId>spring-social-login-cloud-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<artifactId>user-auth-service</artifactId>
<name>user-auth-service</name>
<description>User and Authentication Service</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.1</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.1</version>
<scope>runtime</scope>
</dependency>
<!-- mysql driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>dev.samstevens.totp</groupId>
<artifactId>totp-spring-boot-starter</artifactId>
<version>1.7.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
spring-cloud-starter-netflix-eureka-client
dependency provides Netflix eureka service discovery client and spring-cloud-starter-config
provides client-side support for externalized configuration.
Remove Authentication
We need to update the WebSecurityConfig
to permit all requests without authentication since API Gateway takes care of this.
WebSecurityConfig.java
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().csrf().disable().formLogin().disable().httpBasic().disable()
.exceptionHandling().authenticationEntryPoint(new RestAuthenticationEntryPoint()).and().authorizeRequests().anyRequest().permitAll().and().oauth2Login().authorizationEndpoint()
.authorizationRequestRepository(cookieAuthorizationRequestRepository()).and().redirectionEndpoint().and().userInfoEndpoint().oidcUserService(customOidcUserService)
.userService(customOAuth2UserService).and().tokenEndpoint().accessTokenResponseClient(authorizationCodeTokenResponseClient()).and()
.successHandler(oAuth2AuthenticationSuccessHandler).failureHandler(oAuth2AuthenticationFailureHandler);
// Add our custom Token based authentication filter
http.addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
Modify User Controller
Here, we are just gonna append /users
to the path so that it will be easy to configure routes in the API Gateway.
UserController.java
package com.javachinna.controller;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.javachinna.config.CurrentUser;
import com.javachinna.dto.LocalUser;
import com.javachinna.util.GeneralUtils;
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/me")
@PreAuthorize("hasRole('USER')")
public ResponseEntity<?> getCurrentUser(@CurrentUser LocalUser user) {
return ResponseEntity.ok(GeneralUtils.buildUserInfo(user));
}
@GetMapping("/all")
public ResponseEntity<?> getContent() {
return ResponseEntity.ok("Public content goes here");
}
@GetMapping("/user")
@PreAuthorize("hasRole('USER')")
public ResponseEntity<?> getUserContent() {
return ResponseEntity.ok("User content goes here");
}
@GetMapping("/admin")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<?> getAdminContent() {
return ResponseEntity.ok("Admin content goes here");
}
@GetMapping("/mod")
@PreAuthorize("hasRole('MODERATOR')")
public ResponseEntity<?> getModeratorContent() {
return ResponseEntity.ok("Moderator content goes here");
}
}
Create Main Application Class
UserAuthServiceApplication.java
@EnableEurekaClient
annotation enables Eureka discovery configuration for clients. Use this (optionally) in case you want discovery and know for sure that it is Eureka you want. All it does is turn on discovery and let the autoconfiguration find the eureka classes if they are available (i.e. you need Eureka on the classpath as well).
Instead of using @EnableEurekaClient
, you can also use the generic @EnableDiscoveryClient
annotation which is not specific to any DiscoveryClient
implementation. It enables any DiscoveryClient
implementation available in the classpath.
package com.javachinna;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication(scanBasePackages = "com.javachinna")
@EnableEurekaClient
@EnableJpaRepositories
@EnableTransactionManagement
public class UserAuthServiceApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplicationBuilder app = new SpringApplicationBuilder(UserAuthServiceApplication.class);
app.run();
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(UserAuthServiceApplication.class);
}
}
Modify Application Properties
application.properties
server.port=8084
spring.application.name=user-auth-service
#spring.profiles.active=dev
spring.config.import=configserver:http://localhost:8888
# Database configuration props
spring.datasource.url=jdbc:mysql://localhost:3306/demo?createDatabaseIfNotExist=true
spring.datasource.username=root
spring.datasource.password=secret
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# Hibernate props
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
#spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
gateway.service.url=http://localhost:8080/login/oauth2/code/{registrationId}
# Social login provider props
spring.security.oauth2.client.registration.google.clientId=<your-client-id>
spring.security.oauth2.client.registration.google.clientSecret=<your-client-secret>
spring.security.oauth2.client.registration.google.redirect-uri=${gateway.service.url}
spring.security.oauth2.client.registration.facebook.clientId=<your-client-id>
spring.security.oauth2.client.registration.facebook.clientSecret=<your-client-secret>
spring.security.oauth2.client.registration.facebook.redirect-uri=${gateway.service.url}
spring.security.oauth2.client.provider.facebook.user-info-uri=https://graph.facebook.com/me?fields=id,name,email,picture
spring.security.oauth2.client.registration.github.clientId=<your-client-id>
spring.security.oauth2.client.registration.github.clientSecret=<your-client-secret>
spring.security.oauth2.client.registration.github.redirect-uri=${gateway.service.url}
spring.security.oauth2.client.registration.linkedin.clientId=<your-client-id>
spring.security.oauth2.client.registration.linkedin.clientSecret=<your-client-secret>
spring.security.oauth2.client.registration.linkedin.client-authentication-method=post
spring.security.oauth2.client.registration.linkedin.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.linkedin.scope=r_liteprofile, r_emailaddress
spring.security.oauth2.client.registration.linkedin.redirect-uri=${gateway.service.url}
spring.security.oauth2.client.registration.linkedin.client-name=Linkedin
spring.security.oauth2.client.registration.linkedin.provider=linkedin
spring.security.oauth2.client.provider.linkedin.authorization-uri=https://www.linkedin.com/oauth/v2/authorization
spring.security.oauth2.client.provider.linkedin.token-uri=https://www.linkedin.com/oauth/v2/accessToken
spring.security.oauth2.client.provider.linkedin.user-info-uri=https://api.linkedin.com/v2/me
spring.security.oauth2.client.provider.linkedin.user-name-attribute=id
linkedin.email-address-uri=https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))
################### GMail Configuration ##########################
spring.mail.host=smtp.gmail.com
spring.mail.port=465
spring.mail.protocol=smtps
[email protected]
spring.mail.password=secret
spring.mail.properties.mail.transport.protocol=smtps
spring.mail.properties.mail.smtps.auth=true
spring.mail.properties.mail.smtps.starttls.enable=true
spring.mail.properties.mail.smtps.timeout=8000
[email protected]
app.client.baseUrl=http://localhost:8081/
# After successfully authenticating with the OAuth2 Provider,
# we'll be generating an auth token for the user and sending the token to the
# redirectUri mentioned by the frontend client in the /oauth2/authorization request.
# We're not using cookies because they won't work well in mobile clients.
app.oauth2.authorizedRedirectUris=http://localhost:8081/oauth2/redirect,myandroidapp://oauth2/redirect,myiosapp://oauth2/redirect
# For detailed logging during development
#logging.level.com=TRACE
logging.level.web=debug
#logging.level.org.hibernate.SQL=TRACE
#logging.level.org.hibernate.type=TRACE
- The
spring.application.name
property is used to specify the application/service name. This is the name that gets registered with Service Discovery. Hence, microservices can communicate with each other using this name instead of hostname and port number.
- We have moved some common configurations to the remote git repository which will be served by the Config server on http://localhost:8888. So we have configured the
spring.config.import
property with this URL. - Since the gateway service is the entry point for all incoming requests, we need to use the gateway service URL as the
redirect-uri
for all the social login providers. The gateway service will then forward the request to theuser-auth-service
.
Product Service
Let’s create a new maven project product-service
and move the ProductController
and all of its relevant code to this project.
Project Dependencies
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.javachinna</groupId>
<artifactId>spring-social-login-cloud-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<artifactId>product-service</artifactId>
<version>1.2.0</version>
<name>product-service</name>
<description>Product Service</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Create Main Application Class
ProductServiceApplication.java
package com.javachinna;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication(scanBasePackages = "com.javachinna")
@EnableEurekaClient
@EnableJpaRepositories
@EnableTransactionManagement
public class ProductServiceApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplicationBuilder app = new SpringApplicationBuilder(ProductServiceApplication.class);
app.run();
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(ProductServiceApplication.class);
}
}
Create Application Properties
application.properties
server.port=8082
spring.application.name=product-service
# Database configuration props
spring.datasource.url=jdbc:mysql://localhost:3306/products?createDatabaseIfNotExist=true
spring.datasource.username=root
spring.datasource.password=secret
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# Hibernate props
spring.jpa.show-sql=true
#spring.jpa.hibernate.ddl-auto=none
spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
logging.level.web=INFO
Order Service
Let’s create a new maven project order-service
and move the OrderController
and all of its relevant code to this project.
Project Dependencies
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.javachinna</groupId>
<artifactId>spring-social-login-cloud-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<artifactId>order-service</artifactId>
<version>1.2.0</version>
<name>order-service</name>
<description>Order Service</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- mysql driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.razorpay</groupId>
<artifactId>razorpay-java</artifactId>
<version>1.3.9</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Create Main Application Class
OrderServiceApplication.java
package com.javachinna;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication(scanBasePackages = "com.javachinna")
@EnableEurekaClient
@EnableJpaRepositories
@EnableTransactionManagement
public class OrderServiceApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplicationBuilder app = new SpringApplicationBuilder(OrderServiceApplication.class);
app.run();
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(OrderServiceApplication.class);
}
}
Create Application Properties
application.properties
server.port=8083
spring.application.name=order-service
# Database configuration props
spring.datasource.url=jdbc:mysql://localhost:3306/orders?createDatabaseIfNotExist=true
spring.datasource.username=root
spring.datasource.password=secret
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# Hibernate props
spring.jpa.show-sql=true
#spring.jpa.hibernate.ddl-auto=none
spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
# For detailed logging during development
#logging.level.com=TRACE
logging.level.web=INFO
#logging.level.org.hibernate.SQL=TRACE
#logging.level.org.hibernate.type=TRACE
What’s next?
In this article, we have decomposed the existing monolithic application into 3 different microservices. In the next article, we are gonna create Spring Cloud Config, API Gateway, and Discovery service.