In microservices practice, Spring Cloud Ribbon and Spring Cloud Hystrix are often used together.
Spring Cloud Feign is a higher-level encapsulation of these two basic tools, extending annotation support for Spring MVC on top of Netflix Feign to provide a declarative way to define Web services clients.
Quick start
Start eureka-Server and Hello-service, and create feign-Consumer, a Spring Boot project.
1. Add dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
Copy the code
2. Annotation enable Feign
package com.ulyssesss.feignconsumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class FeignConsumerApplication {
public static void main(String[] args) { SpringApplication.run(FeignConsumerApplication.class, args); }}Copy the code
3. Define the HelloService interface
package com.ulyssesss.feignconsumer.service;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient("hello-service")
public interface HelloService {
@GetMapping("hello")
String hello(@RequestParam("p1") String p1, @RequestParam("p2") String p2);
}
Copy the code
Where @FeignClient specifies the service name, and the Spring MVC annotation binds the concrete REST interface and request parameters.
Note that the @requestParam, @requestheader annotation value cannot be omitted when defining the parameter binding. Spring MVC uses the parameter name as the default value, but it must be specified by value in Feign.
4. Write the Controller
package com.ulyssesss.feignconsumer.web;
import com.ulyssesss.feignconsumer.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class FeignConsumerController {
@Autowired
HelloService helloService;
@GetMapping("hello")
public String hello(@RequestParam String p1, @RequestParam String p2) {
System.out.println("feign consumer get hello");
returnhelloService.hello(p1, p2); }}Copy the code
5. Set the address of the service registry
spring.application.name=feign-consumer
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
Copy the code
Launch all applications, visit http://localhost:8080/hello? P1 =a&p2=b, feign-consumer calls the Hello-service with a declarative service call, returning Hello, a, b.
Inheritance features
When binding a service interface using Spring MVC annotations, it can be almost completely copied from the service provider’s Controller, so you can take advantage of Feign’s inheritance features for further abstraction, reuse REST interface definitions and reduce coding.
1. Add dependencies
Create Maven project hello-service-API. Add spring-boot-starter-web dependency because Spring MVC annotations are required.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>provided</scope>
</dependency>
Copy the code
2. Define interfaces and Dtos
Define reusable Dtos and interface definitions in hello-service-API.
package com.ulyssesss.helloserviceapi.service;
import com.ulyssesss.helloserviceapi.dto.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
public interface HelloService {
@GetMapping("hello")
String hello(@RequestParam("p1") String p1, @RequestParam("p2") String p2);
@GetMapping("user")
User user(a);
@PostMapping("post")
String post(a);
}
Copy the code
package com.ulyssesss.helloserviceapi.dto;
public class User {
private String name;
private int age;
public User(a) {}
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString(a) {
return "User{" + "name='" + name + '\' ' + ", age=" + age + '} ';
}
// set get
}
Copy the code
3.改写 hello-service
Introduce hello-service-API dependency in hello-service, override HelloController.
package com.ulyssesss.helloservice.web;
import com.ulyssesss.helloserviceapi.dto.User;
import com.ulyssesss.helloserviceapi.service.HelloService;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController implements HelloService {
@Override
public String hello(@RequestParam String p1, @RequestParam String p2) {
System.out.println("hello service get hello");
return "hello, " + p1 + "," + p2;
}
@Override
public User user(a) {
System.out.println("hello service get user");
return new User("Jack".22);
}
@Override
public String post(a) {
System.out.println("hello service post");
return "post"; }}Copy the code
4. Rewrite the feign – consumer
Introduce the hello-service-API dependency in Feign-Consumer and create RefactorHelloService that inherits from HelloService.
package com.ulyssesss.feignconsumer.service;
import com.ulyssesss.helloserviceapi.service.HelloService;
import org.springframework.cloud.netflix.feign.FeignClient;
@FeignClient(name = "hello-service")
public interface RefactorHelloService extends HelloService {}Copy the code
Modify FeignConsumerController and inject RefactorHelloService.
package com.ulyssesss.feignconsumer.web;
import com.ulyssesss.feignconsumer.service.RefactorHelloService;
import com.ulyssesss.helloserviceapi.dto.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class FeignConsumerController {
@Autowired
RefactorHelloService refactorHelloService;
@GetMapping("hello")
public String hello(@RequestParam String p1, @RequestParam String p2) {
System.out.println("feign consumer get hello");
return refactorHelloService.hello(p1, p2);
}
@GetMapping("user")
public User user(a) {
System.out.println("feign consumer get user");
return refactorHelloService.user();
}
@PostMapping("post")
public String post(a) {
System.out.println("feign consumer post");
returnrefactorHelloService.post(); }}Copy the code
Launch all applications, visit http://localhost:8080/hello? P1 =a&p2=b, feign-consumer calls the Hello-service with a declarative service call, returning Hello, a, b.
Using Spring Cloud Feign’s inheritance features, interfaces can be glassed out of the Controller and shared with Maven’s private repository, reducing binding configurations for service consumers.
Ribbon and Hystrix configuration
Spring Cloud Feign’s client load balancing is implemented through the Spring Cloud Ribbon, which can be configured to define client call parameters. The configurations of Riibon and Hystrix are as follows:
Spring. The application. The name = feign - consumer eureka. Client. The service - url. DefaultZone = http://localhost:8761/eureka/ # # enable hystrix Feign. Hystrix. Enabled = true # # hystrix.com global timeout fusing time mand. Default. Execution. The isolation. Thread. TimeoutInMilliseconds = 10000 Ribbon.ConnectTimeout=250 ribbon.ReadTimeout=10000 ribbon Ribbon. OkToRetryOnAllOperations = false # # for the hello - service service, Retry the instance number switch hello - service. Ribbon. MaxAutoRetriesNextServer = 1 # # for the hello - service service, For the current instance retries hello - service. Ribbon. MaxAutoRetries = 0Copy the code
Service degradation
The service degradation provided by Hystrix is an important method of fault tolerance. Because Feign encapsulates HystrixCommand’s definition when defining the service client, the fallback parameter of @HystrixCommand cannot specify the degradation logic.
Spring Cloud Feign provides a simple way to define service degradation by creating HelloServiceFallback to implement the HelloService interface and declare it as a Bean via @Component, Implement the specific degrade logic in HelloServiceFallback, and finally declare the Bean handling the degrade logic in @FeignClient via the FallBack property.
package com.ulyssesss.feignconsumer.service;
import com.ulyssesss.helloserviceapi.dto.User;
import org.springframework.stereotype.Component;
@Component
public class HelloServiceFallback implements RefactorHelloService {
@Override
public String hello(String p1, String p2) {
return "error";
}
@Override
public User user(a) {
return new User("error".0);
}
@Override
public String post(a) {
return "error"; }}Copy the code
package com.ulyssesss.feignconsumer.service;
import com.ulyssesss.helloserviceapi.service.HelloService;
import org.springframework.cloud.netflix.feign.FeignClient;
@FeignClient(name = "hello-service", fallback = HelloServiceFallback.class)
public interface RefactorHelloService extends HelloService {}Copy the code
After starting the service, disconnect the hello-service from the service provider and access the Feign-Consumer interface, which performs the degradation logic as defined in HelloServiceFallback.
The original address
The sample code welcomes Star