Skip to main content

Microservices with Spring Boot - complete tutorial

In this tutorial we are going to learn how to develop microservices using spring boot with examples. Main focus of this tutorial is on learning by doing hands-on. Before hands-on we will first understand what is microservices and related terminologies like DDD, 12-Factors App, Dev Ops.

What is a Microservice

In simple terms microservice is a piece of software which has a single responsibility and can be developed, tested & deployed independently. In microservices we focus on developing independent and single fully functioning modules.
Opposite to microservice, with monolithic application it focuses on all the functionality or modules in a single application. So when any changes required to monolithic application it has to deploy and test the complete application while with microservice it has to develop and deploy only affected component which is a small service. It saves lot of development and deployment time in a large application.
It's basically an architectural style which can be followed to develop an application as a small service which is independent or may be interdependent (talking to other service to complete the job).

Designing Microservice

While designing application developers and domain experts should speak the same language so both have the same understanding. When we design a microservice we need to follow specific approach/ patterns, for example: DDD. When developing microservice then we need to make sure that our microservice implements certain attributes, for example: 12-factors. And then we can have other common design pattern/principles for  application development.

1. What is Domain driven design (DDD)

DDD is a top to bottom design approach similar to OOAD which helps to reflect the business domain into software. It helps defining the domains, elements, their relationship, boundary and communication to replicate the real business. That's why we say it focuses on the business domain and good domain knowledge is required to design the system perfectly. Having complete domain knowledge is good for any application but in my experience I have seen when developers know only the portion of application where they are working actually. But when we design system in small pieces it becomes very important to understand the whole system and how these pieces will communicate with each other where they reflects a unit of the real business. A proper understanding helps in designing the clear interfaces for behaviour and communication between components.

2. What are the Twelve-Factors

Twelve factors are defined as a must have attributes for any service to be developed as "Software as a Service". These attributes are well suited for microservices. While developing a microservice we can design and test it against these factors to verify the various aspect of a microservice.
Below are the twelve factors which I have copied from Wikipedia for your ease.

#FactorDescription
ICodebaseThere should be exactly one codebase for a deployed service with the codebase being used for many deployments.
IIDependenciesAll dependencies should be declared, with no implicit reliance on system tools or libraries.
IIIConfigConfiguration that varies between deployments should be stored in the environment.
IVBacking servicesAll backing services are treated as attached resources and attached and detached by the execution environment.
VBuild, release, runThe delivery pipeline should strictly consist of build, release, run.
VIProcessesApplications should be deployed as one or more stateless processes with persisted data stored on a backing service.
VIIPort bindingSelf-contained services should make themselves available to other services by specified ports.
VIIIConcurrencyConcurrency is advocated by scaling individual processes.
IXDisposabilityFast startup and shutdown are advocated for a more robust and resilient system.
XDev/Prod parityAll environments should be as similar as possible.
XILogsApplications should produce logs as event streams and leave the execution environment to aggregate.
XIIAdmin ProcessesAny needed admin tasks should be kept in source control and packaged with the application.

This twelve factors attribute specifies almost most of the thing to be taken care for microservices development but still there are several patterns which can be applied as per business requirement. For example Database per Service pattern also can be used which says each microservice should have it's own database and it must not be shared by other services.

Developing Microservice

As a part of microservice development, we will create a microservice, cloud config server, service registry or discovery server and API gateway. Below architecture depicts the implementation of all components in our example application.

microservice architecture

Now in further sections we will see the development of all components mentioned in above architecture.
  1. API Gateway

  2. API gateway provides a single entry point to all associated microservices, either directly or through discovery server. It's very useful to access group of services from different providers. There are many other things we can do at API gateway like, auhtentication/authorization, running interceptor codes, filters, logging etc.
    However in this example we are using only single microservice with API gateway but we can register multiple microservices at a time.
    Please refer below post for detailed tutorial and source code.
    Spring cloud API Gateway
  3. Discovery Server (Service Registry)

  4. Discovery server provides capability to microservices to register themselves and allows clients to discover these microservices.
    Please refer below post for detailed tutorial and source code.
    Registry/ discovery server using Spring boot and Eureka
  5. User Management Service (Microservice)

  6. User management service is a REST based microservice and have below dependencies to run the application.
    • Cloud config server for configuration management
    • RabbitMQ to subscribe the refresh event published by cloud config server
    • Discovery server for service registration
    • Mongo DB for persistence store
    Below are the endpoints published by this service.
    • /users: It displays a welcome message
    • /users/{ID}: Provides the details for given user ID.
    • /users/create: Creates new user and returns user ID.
    • /users/listAll: Returns a list of all existing users.
    Required code and configurations are as given below.
    • Maven dependencies
    •         <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-data-mongodb</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-web</artifactId>
              </dependency>
              <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-actuator</artifactId>
              </dependency>
      
    • Main class (Spring boot class)
    • @EnableDiscoveryClient //required to register itself with eureka discovery server
      @SpringBootApplication
      @ComponentScan(basePackages = {"com.ttj"})
      public class UserMgmtServiceApplication {
      
          public static void main(String[] args) {
              SpringApplication.run(UserMgmtServiceApplication.class, args);
          }
      }
      
    • Configuration (bootstrap.yml)
    • server.port : 8080
      spring:
        application.name: UserManagementService
        cloud:
          config:
      #config server details
            name: microservices-config
            uri: http://localhost:8888/
            username: config_user
            password: config_user
      #rabbit mq to subscribe to refresh events published by config server
        rabbitmq:
          host: localhost
          port: 5672
          virtual-host: /
          username: guest
          password: guest
        profiles:
          active: DEV
        data:
      #mongo DB configuraitons
          mongodb:
            database: microservice
            host: localhost
            port: 27017
            repositories:
              type: auto
            uri: mongodb://localhost:27017/microservice
      #Eureka server configurations to register itself
      eureka:
        client:
          serviceUrl:
            defaultZone: http://localhost:8089/eureka
      
    • Domain Object (User)
    • @Document(collection = "appusers")
      public class User {
          @Id
          private String id;
          private String userId;
          private String firstName;
          private String lastName;
          private Integer age;
      
          public User() {}
          public User(String userId, String firstName, String lastName, Integer age) {
              super();
              this.userId = userId;
              this.firstName = firstName;
              this.lastName = lastName;
              this.age = age;
          }
          //getter methods
          //setter methods
      
          @Override
          public String toString() {
              return userId+", "+firstName+", "+lastName+", "+age;
          }
      }
      
    • Repository Interface
    • public interface UserRepository extends MongoRepository<User, String> {
          @Query("{ 'userId' : ?0 }")
          public User findByUserId(String userId);
      }
      
    • Service Implementation (Business Logic)
    • @Service
      public class UserMgmtServiceImpl implements UserMgmtService{
          @Autowired
          UserRepository userRepo;
      
          @Override
          public void saveUser(User user) {
              userRepo.save(user);
          }
      
          @Override
          public User findByUserId(String userId) {
              return userRepo.findByUserId(userId);
          }
      
          @Override
          public void deleteUser(String userId) {
              User user = userRepo.findByUserId(userId);
              userRepo.delete(user);
          }
      
          @Override
          public List listAllUsers(){
              return userRepo.findAll();
          }
      }
      
    • Rest Service Endpoints
    • @RestController
      @RequestMapping("/users")
      @RefreshScope
      public class UserMgmtEndpoint {
      
          @Autowired
          private UserMgmtService userMgmtService;
      
          @Value("${message}")
          private String message;
      
          @RequestMapping(method = RequestMethod.GET, produces = "application/json")
          public String welcome() {
              return message;
          }
      
          @RequestMapping(value="/{userId}", method = RequestMethod.GET, produces = "application/json")
          public User findUserById(@PathVariable("userId") String userId) {
              User user = userMgmtService.findByUserId(userId);
              return user;
          }
      
          @RequestMapping(value = "/create", method = RequestMethod.POST, consumes = "application/json")
          public String createUser(@RequestBody User user) {
              userMgmtService.saveUser(user);
              return "UserId: "+user.getId();
          }
      
          @RequestMapping(value = "/listAll", method = RequestMethod.GET, produces = "application/json")
          public List<User> listUsers() {
              return userMgmtService.listAllUsers();
          }
      }
      

    Source Code

    Complete source code for this microservice is available in below Git location.
    https://github.com/thetechnojournals/microservices/tree/master/user-mgmt-service
  7. Cloud Config Server (Configuration management)

  8. Cloud Config server is used here to provide the distributed configuration management. Client applications connect to config server and access related configurations. To develop a microservice, configurations must be stored in separate place and available on demand. Using config server microservices can subscribe to config server and pull the latest configurations immediately after any config change in config server.
    For complete implementation and more details please refer below post on cloud config server.
    Cloud config server implementation with example 

Running and Testing service

To start the service we need to run it in below order.

  1. Start RabbitMQ and Cloud config server
  2. Start Discovery server
  3. Start MongoDB and Microservice
  4. Start API Gateway

Now you can enter below URL to test the service directly.
http://localhost:8080/users
To test the service through API gateway and discovery server, you need to open below URL in browser.
http://localhost:9999/users/

Both of the above URLs will give you same results.

Comments

Post a comment

Popular Posts

SpringBoot - @ConditionalOnProperty example for conditional bean initialization

@ConditionalOnProperty annotation is used to check if specified property available in the environment or it matches some specific value so it can control the execution of some part of code like bean creation. It may be useful in many cases for example enable/disable service if specific property is available. Below are the attributes which can be used for property check.
havingValue - Provide the value which need to check against specified property otherwise it will check that value should not be false.matchIfMissing - If true it will match the condition and execute the annotated code when property itself is not available in environment.name - Name of the property to be tested. If you want to test single property then you can directly put the property name as string like "property.name" and if you have multiple properties to test then you can put the names like {"prop.name1","prop.name2"}prefix - It can be use when you want to apply some prefix to all prop…

Asynchronous REST service implementation in Spring boot

In this tutorial we will see how to create an asynchronous REST service endpoint using Spring boot application.
Asynchronous service works in a way that it will not block the client request and do the processing in separate thread. When work is complete the response returned to the client so our service will be able to handle more client requests at the same time, compare to synchronous processing model.
Let's understand how it is working in synchronous mode. In such server/client application at server side it has a pool of threads which are serving the request. If a request received by a thread then it will be blocked until it send the response back to client. In this case if processing doesn't take much time it will be able to process it quickly and accept other client requests but there could be one situation when all threads are busy and not able to accept the new client requests.

To overcome of such problems, asynchronous processing model introduced for REST services. In…

Entity to DTO conversion in Java using Jackson

It's very common to have the DTO class for a given entity in any application. When persisting data, we use entity objects and when we need to provide the data to end user/application we use DTO class. Due to this we may need to have similar properties on DTO class as we have in our Entity class and to share the data we populate DTO objects using entity objects. To do this we may need to call getter on entity and then setter on DTO for the same data which increases number of code line. Also if number of DTOs are high then we need to write lot of code to just get and set the values or vice-versa.
To overcome this problem we are going to use Jackson API and will see how to do it with minimal code only.
Maven dependency <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.9</version> </dependency> Entity class Below is our ent…

Web scraper using JSoup and Spring Boot

What is webscraping Webscraping is a technique to extract or pull the data from a website to gather required information by parsing the HTML source of their websites, such as articles from news or books site, products information from online shopping sites or course information from education sites. There are many organisations who uses web scraper to provide the best experience to their customers, for example extract the price for a smartphone from multiple online websites and show their customers the best and cheap product URL.
We will learn here how to code a web scraper by developing a simple new scraper service.
News scraper News scraper is used to extract the news articles or other related contents from a news site. Here we are going to create a web scraper application to pull the articles from news site.
Below are the operations provided by our news scraper service.
List all the authorsSearch articles by author nameSearch articles by article titleSearch articles by article desc…