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

  1. I am appreciative of this blog's ability to provide information on such an important subject. I discovered other segments here, and I'm excited to put these new instructions to use. test tag perth

    ReplyDelete
  2. Thanks for a very interesting blog. What else may I get that kind of info written in such a perfect approach? I’ve a undertaking that I am simply now operating on, and I have been at the look out for such info. how much does it cost to advertise on domain.com.au

    ReplyDelete
  3. I really enjoyed your blog posts, thank you

    ReplyDelete
  4. Thank you for writingg this

    ReplyDelete

Post a Comment

Popular Posts

Setting up kerberos in Mac OS X

Kerberos in MAC OS X Kerberos authentication allows the computers in same domain network to authenticate certain services with prompting the user for credentials. MAC OS X comes with Heimdal Kerberos which is an alternate implementation of the kerberos and uses LDAP as identity management database. Here we are going to learn how to setup a kerberos on MAC OS X which we will configure latter in our application. Installing Kerberos In MAC we can use Homebrew for installing any software package. Homebrew makes it very easy to install the kerberos by just executing a simple command as given below. brew install krb5 Once installation is complete, we need to set the below export commands in user's profile which will make the kerberos utility commands and compiler available to execute from anywhere. Open user's bash profile: vi ~/.bash_profile Add below lines: export PATH=/usr/local/opt/krb5/bin:$PATH export PATH=/usr/local/opt/krb5/sbin:$PATH export LDFLAGS=...

Why HashMap key should be immutable in java

HashMap is used to store the data in key, value pair where key is unique and value can be store or retrieve using the key. Any class can be a candidate for the map key if it follows below rules. 1. Overrides hashcode() and equals() method.   Map stores the data using hashcode() and equals() method from key. To store a value against a given key, map first calls key's hashcode() and then uses it to calculate the index position in backed array by applying some hashing function. For each index position it has a bucket which is a LinkedList and changed to Node from java 8. Then it will iterate through all the element and will check the equality with key by calling it's equals() method if a match is found, it will update the value with the new value otherwise it will add the new entry with given key and value. In the same way it check for the existing key when get() is called. If it finds a match for given key in the bucket with given hashcode(), it will return the value other...

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 ...

Multiple data source with Spring boot, batch and cloud task

Here we will see how we can configure different datasource for application and batch. By default, Spring batch stores the job details and execution details in database. If separate data source is not configured for spring batch then it will use the available data source in your application if configured and create batch related tables there. Which may be the unwanted burden on application database and we would like to configure separate database for spring batch. To overcome this situation we will configure the different datasource for spring batch using in-memory database, since we don't want to store batch job details permanently. Other thing is the configuration of  spring cloud task in case of multiple datasource and it must point to the same data source which is pointed by spring batch. In below sections, we will se how to configure application, batch and cloud task related data sources. Application Data Source Define the data source in application properties or yml con...