How it works...

Similar to what we saw in the previous recipe, the use of the @EnableFeignClients annotation on the main application class, BookPubApplication, explicitly tells Spring Cloud that it should scan for all the interfaces annotated with @FeignClient and create service client implementations based on their definitions. The @EnableFeignClients annotation is similar in nature to the @ComponentScan one, providing attributes to control which packages to scan for the @FeignClient annotated classes or explicitly list the API classes that should be used.

Out of the box, all Feign client implementations are configured using components defined in the FeignClientsConfiguration class, but one can provide alternative configuration classes using the defaultConfiguration attribute of the @EnableFeignClients annotation.

In a nutshell, every interface definition, annotated with @FeignClient, gets a service implementation consisting of a Java dynamic proxy object, which handles all the interface method calls (usually using FeignInvocationHandler to handle all the requests). The invocation handler is responsible for doing a few things.

Once any method is invoked, first the service instances are located using the provided discovery client (in our case it is ConsulDiscoveryClient) based on the name attribute of the @FeignClient annotation. In our example, we have declared the value of name attribute to be http://BookPub-ch9, so all the service instances from the registry which have their name set to BookPub-ch9 will be returned as possible candidates. This name can be just a service name itself, or, as we did in our example, an optional protocol can be specified. This is a useful feature, as not all service discovery providers support ability to specify exactly how the service should be called, so if we want to make a secure call using HTTPS, we can explicitly specify the protocol to help Feign make the right call.

There are a number of other configuration attributes available on the annotation, for example, to tell Feign to make a direct call to a specified URL instead of doing a service lookup, there is a url attribute that can be configured.

To see a complete list of possible attributes and their use-cases, go to https://cloud.spring.io/spring-cloud-netflix/single/spring-cloud-netflix.html#spring-cloud-feign.

The list of instances for a given service gets wrapped with an internal load balancer, provided by another Netflix library—Ribbon. It uses a specified algorithm to rotate between the instances of a service as well as to take the bad instances out of circulation if the discovery client says they are unhealthy.

To see a complete list of possible configuration options for things like load balancing rules, and other settings, go to https://cloud.spring.io/spring-cloud-netflix/single/spring-cloud-netflix.html#spring-cloud-ribbon.

When a specific instance has been determined, an HTTP request gets created, using the standard Spring HttpMessageConverter beans to transform the method arguments into HTTP request path variables and query parameters. After all that is done, the request gets sent using a configured HTTP client and the response gets converted into a return type declared on the API interface using the same converters.

Now that we know what @FeignClient annotation is all about and what happens under the hood once an API-defined method gets invoked, let's take a look at how to annotate the interface methods that should be translated into remote service calls. Conveniently, and done so on purpose, we can use exactly the same annotations as we are already used to, when declaring controller mappings inside the @Controller annotated classes. Each method in our API interface, which we want to map to a remote service, should be annotated with the @RequestMapping annotation. The path attribute corresponds to a URL path of the remote service we want to invoke.

In our example, we want to call our BookController.getBook(...) method, which translates to the /books/{isbn} URL path. This is exactly what we put as a value for the path attribute, and make sure we also annotate the isbn argument in our findBookByIsbn(...) method with @PathVariable("isbn") to link it to a {isbn} placeholder in the mapping template.

As a general rule of thumb, the @RequestMapping annotation functions exactly the same as if it were used in a controller, except the configuration relates to an outgoing request instead of an inbound one. It might be especially confusing when configuring the consumes attribute of the annotation, that is, consumes = "application/json", because it indicates that it is a remote side that expects JSON as a content-type of the payload.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.247.31