You are here
Home > java >

Spring Cloud Annotations With Examples

Spring Cloud Annotations With ExamplesIntroduction of new Annotations reduces the development efforts day by day. Needless to say, as a developer, we can’t think of the development of an enterprise level application without using annotations, especially in applications that use Spring or related frameworks. Furthermore, we come across the Spring Cloud framework when we develop a Microservices based application. Now-a-days, there is a high demand of Microservices based applications in the industry. Therefore, it becomes very crucial to know the annotations used in Spring Cloud. Hence, in this article, we are going to discuss ‘Spring Cloud Annotations With Examples’.

We can’t deny from the fact that the cloud is the future and, in the upcoming days, we will be seeing a lot of Java based applications deployed in the cloud. So, it’s better to learn and master the Spring Cloud. In the future it might become the standard framework to develop cloud-based Java applications. Let’s start discussing about our topic ‘Spring Cloud Annotations With Examples’ and the related concepts.

@EnableEurekaServer

When you develop a Microservices based project using Spring Boot & Spring Cloud, this will be the first annotation that you will apply to the main class of a microservice to make it a Eureka Server. As the name suggests, we want to enable Eureka Server. We will use this annotation in the context of Service Registry & Discovery. In the concept of Service Registry, every microservices registers itself with Eureka server. On the other hand, Service Discovery is the concept where one microservice discovers other microservice with the help of its entry in the Eureka server. In order to learn more about Eureka, kindly visit Netflix Eureka Service Registry & Discovery.

Moreover, on using Spring Cloud’s annotation @EnableEurekaServer, other microservices can register here and communicate with each other via service discovery. For example, in order to make your application/microservice acts as Eureka server, we need to apply @EnableEurekaServer at the main class of your application as shown below.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer
@SpringBootApplication
public class SpringCloudEurekaServerApplication {

    public static void main(String[] args) {
       SpringApplication.run(SpringCloudEurekaServerApplication.class, args);
    }
}

@EnableEurekaClient

This annotation relates to the concept of Service Discovery in Microservices. Using Service Discovery, one microservice can communicate with the other microservice via Eureka Server. Hence, other microservices who wants to register with Eureka Server & get discovered with the help of Eureka Server, become the candidate for this annotation.

In order to make your application/microservice acts as a Eureka discovery client, you need to apply @EnableEurekaClient at the main class of your application as shown below.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@EnableEurekaClient
@SpringBootApplication
public class SpringCloudPaymentServiceApplication {

   public static void main(String[] args) {
      SpringApplication.run(SpringCloudCartServiceApplication.class, args);
   }
}

@EnableFeignClients

In Microservices, communication among multiple services happens on the concept of producer-consumer. Moreover, the Consumer service will consume the services published by producer service. At the consumer side we apply this annotation. Feign is a declarative REST Client. It makes writing web service clients easier.

In order to get the features of OpenFeign, we will additionally need to apply @EnableFeignClients at the main class as below.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class SpringCloudFeignStudentServiceApplication {

     public static void main(String[] args) {
        SpringApplication.run(SpringCloudFeignStudentServiceApplication.class, args);
     }
}

@FeignClient(name=”ApplicationName”)

This annotation comes with the annotation @EnableFeignClients. At Consumer’s Interface level, we need to apply @FeignClient annotation and provide the name of producer service/application. For example, below code snippet demonstrate the concept.

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import com.dev.springcloud.feign.model.Book;

@FeignClient(name="BOOK-SERVICE")
public interface BookRestConsumer {

      @GetMapping("/book/data")
      public String getBookData();

      @GetMapping("/book/{id}")
      public Book getBookById(@PathVariable Integer id);

      @GetMapping("/book/all")
      public List<Book> getAllBooks();

      @GetMapping("/book/entity")
      public ResponseEntity<String> getEntityData();
}

Furthermore, in order to receive the data from Book service, we need to auto-wire the BookRestConsumer where it is required. Additionally, for more details on Feign Client related concepts, kindly visit a separate article on ‘How To Implement Feign Client In Spring Boot Microservices?‘.

@EnableConfigServer

Config Server is a central configuration server that provides configurations (properties) to each microservice connected to it. In order to make a Microservice acts as Config Server, we need to apply @EnableConfigServer annotation at the main class of the microservice. For example, below code snippet demonstrates the use of @EnableConfigServer annotation.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableConfigServer
public class SpringCloudConfigServerApplication {

    public static void main(String[] args) {
       SpringApplication.run(SpringCloudFeignBookServiceApplication.class, args);
    }
}

Furthermore, Spring Cloud Config Clients are the microservices that utilize the services provided by Spring Cloud Config Server. You may visit a separate detailed article on ‘How To Implement Spring Cloud Config Server In Microservices?‘ and the related concepts.

Annotations On Fault Tolerance provided by Resilience4j

In a context of Microservices, Fault Tolerance is a technique of tolerating a fault. A Microservice that tolerates the fault is known as Fault Tolerant. Moreover, a Microservice should be a fault tolerant in such a way that the entire application runs smoothly. There are possibilities of various kinds of faults after running a microservices based application. In order to implement this technique, the Resilience4j offers us a variety of modules based on the type of fault we want to tolerate. Here, we will be discussing the annotations used for different types of faults. For complete details on Resilience4j API, kindly visit our separate article on ‘How To Implement Fault Tolerance In Microservices Using Resilience4j?’.

@RateLimiter

Rate Limiter limits the number of requests for a given period. There are various reasons to limit the number of requests that an API can handle, such as protect the resources from spammers, minimize the overhead, meet a service level agreement and many others. We can achieve this functionality with the help of annotation @RateLimiter provided by Resilience4j without writing a code explicitly. For example, below code snippet demonstrates the functionality of @RateLimiter applied on a method.

@GetMapping("/getMessage")
@RateLimiter(name = "getMessageRateLimit", fallbackMethod = "getMessageFallBack")
public ResponseEntity<String> getMessage(@RequestParam(value="name", defaultValue = "Hello") String name){

    return ResponseEntity.ok().body("Message from getMessage() :" +name);
}

@Retry 

Suppose Microservice ‘A’  depends on another Microservice ‘B’. Let’s assume Microservice ‘B’ is a faulty service and its success rate is only upto 50-60%. However, fault may be due to any reason, such as service is unavailable, buggy service that sometimes responds and sometimes not, or an intermittent network failure etc. However, in this case, if Microservice ‘A’ retries to send request 2 to 3 times, the chances of getting response increases. We can achieve this functionality with the help of annotation @Retry provided by Resilience4j without writing a code explicitly. For example, below code snippet demonstrates the functionality of @RateLimiter applied on a method.

@GetMapping("/getInvoice")
@Retry(name = "getInvoiceRetry", fallbackMethod = "getInvoiceFallback") 
public String getInvoice() {
   logger.info("getInvoice() call starts here");
   ResponseEntity<String> entity= restTemplate.getForEntity("http://localhost:8080/invoice/rest/find/2", String.class);
   logger.info("Response :" + entity.getStatusCode());
   return entity.getBody();
}

@CircuitBreaker

As the name suggests, ‘Breaking the Circuit’. Suppose a Microservice ‘A’ is internally calling another Microservice ‘B’ and ‘B’ has some fault. Needless to say, in Microservice Architecture ‘A’ might be dependent on other Microservices and the same is true for Microservice ‘B’. In order to escape the multiple microservices from becoming erroneous as a result of cascading effect, we stop calling the faulty Microservice ‘B’. Instead, we call a dummy method that is called a ‘Fallback Method’. Therefore, calling a fallback method instead of an actual service due to a fault is called breaking the circuit.

Using Circuit Breaker we can eliminate the flow of failures to downstream/upstream. We can achieve this functionality easily with the help of annotation @CircuitBreaker without writing a specific code. For example, below code demonstrates the concept of @CircuitBreaker that is applied on a method.

@GetMapping("/getInvoice")
@CircuitBreaker(name = "getInvoiceCB", fallbackMethod = "getInvoiceFallback") 
public String getInvoice() { 
   logger.info("getInvoice() call starts here");
   ResponseEntity<String> entity= restTemplate.getForEntity("http://localhost:8080/invoice/rest/find/2", String.class);
   logger.info("Response :" + entity.getStatusCode());
   return entity.getBody();
}

@Bulkhead

In the context of the Fault Tolerance mechanism, if we want to limit the number of concurrent requests, we can use Bulkhead as an aspect. Using Bulkhead, we can limit the number of concurrent requests within a particular period. We can achieve this functionality easily with the help of annotation @Bulkhead without writing a specific code. For example, below code snippet demonstrates the usage of annotation @Bulkhead that is applied on a method.

@GetMapping("/getMessage")
@Bulkhead(name = "getMessageBH", fallbackMethod = "getMessageFallBack")
public ResponseEntity<String> getMessage(@RequestParam(value="name", defaultValue = "Hello") String name){

    return ResponseEntity.ok().body("Message from getMessage() :" +name);
}

@Timelimiter

Time Limiting is the process of setting a time limit for a Microservice to respond. Suppose Microservice ‘A’ sends a request to Microservice ‘B’, it sets a time limit for the Microservice ‘B’ to respond. If  Microservice ‘B’ doesn’t respond within that time limit, then it will be considered that it has some fault. We can achieve this functionality easily with the help of annotation @Timelimiter without writing a specific code. For example, below code demonstrates the usage of @Timelimiter.

@GetMapping("/getMessageTL")
@TimeLimiter(name = "getMessageTL")
public CompletableFuture<String> getMessage() {
   return CompletableFuture.supplyAsync(this::getResponse);
}

For complete examples of all Fault Tolerance annotations, kindly visit the separate article on ‘How To Implement Fault Tolerance In Microservices Using Resilience4j?’.

 

 

close

Leave a Reply

Top