In the previous section, we used Ribbon (Http/Tcp-based) to make microservice calls. Ribbon's calls are simple, intercept the requested service through the Ribbon component, get the IP:Port of the service instance through Eureka Server, and then invoke the API.In this lesson, we use a simpler way, using a declarative Web service client Feign, we only need to use Feign to declare the interface, and use annotations to configure it so we can use it, isn't it simple?In practice, we only use Feign to make calls between services (most of them).Next, let's take a sample action.
For code reuse, let's create a new project mscx-ad-feign-sdk as a Feign service invocation tool.
- Create project mscx-ad-feign-sdk
- Step 1 of Trilogy (Additional Dependency)
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>mscx-ad</artifactId> <groupId>com.sxzhongf</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <packaging>jar</packaging> <name>mscx-ad-feign-sdk</name> <description>Define only microservices Feign The call uses both the request object and the response object, regardless of the specific implementation class.</description> <groupId>com.sxzhongf</groupId> <artifactId>mscx-ad-feign-sdk</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Components that introduce service calls feign rely on--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>com.sxzhongf</groupId> <artifactId>mscx-ad-common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!-- Introducing system fault tolerance hystrix Dependency on--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> <version>1.2.7.RELEASE</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
- Step 2 of the Trilogy (annotated @EnableFeignClients, added to specific microservices, using our custom FeignClient)
/** * ISponsorFeignClient for service using * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | If initial </a> */ @FeignClient(value = "mscx-ad-sponsor", fallback = SponsorClientHystrix.class) public interface ISponsorFeignClient { @RequestMapping(value = "/ad-sponsor/plan/get", method = RequestMethod.POST) CommonResponse<List<AdPlanVO>> getAdPlansUseFeign(@RequestBody AdPlanGetRequestVO requestVO); @RequestMapping(value = "/ad-sponsor/user/get", method = RequestMethod.GET) /** * Feign If buried in a pit is a Get request, you must add {@link RequestParam} before all parameters. You cannot use {@link Param} * It is automatically forwarded as a POST request. */ CommonResponse getUsers(@RequestParam(value = "username") String username); } --- @RestController @Slf4j @RequestMapping(path = "/search-feign") public class SearchFeignController { /** * Inject our custom FeignClient */ private final ISponsorFeignClient sponsorFeignClient; @Autowired public SearchFeignController(ISponsorFeignClient sponsorFeignClient) { this.sponsorFeignClient = sponsorFeignClient; } @GetMapping(path = "/user/get") public CommonResponse getUsers(@Param(value = "username") String username) { log.info("ad-search::getUsersFeign -> {}", JSON.toJSONString(username)); CommonResponse commonResponse = sponsorFeignClient.getUsers(username); return commonResponse; } }
- Step 3 of the Trilogy (Configured, Tool Class Library not required, added in specific microservices)
One of the problems with our example above is that if there is a problem with our advertising service, we will make an error by using API sponsorFeignClient.getUsers (username) called by FeignClient; if we make a long-term error, it will cause a large-scale service error problem, which is what we often call service snow.Collapse effect, how do we avoid a problem where a service error is causing the whole system to collapse?Here we need to introduce a component, Hystrix, to handle service errors.
- Step1 for Trilogy (Additional Dependency)
From the figure above, we can see that when we introduced a Feign dependency, it was already dependent on Hystrix itself. Based on the transitivity of Maven dependencies, we can know that our own services already contain Hystrix dependency support, and we can use ~
- Triple Step2 @EnableHystrix //Turn on hystrix circuit breaker
- Step3 for Trilogy (Configuration Change)
feign: hystrix: enabled: true
- Use Hystrix to configure Feign to implement call fault tolerance
@Component public class SponsorClientHystrix implements ISponsorFeignClient { @Override public CommonResponse<List<AdPlanVO>> getAdPlansUseFeign(AdPlanGetRequestVO requestVO) { return new CommonResponse<>(-1, "mscx-ad-sponsor feign & hystrix get plan error."); } @Override public CommonResponse getUsers(String username) { return new CommonResponse<>(-1, "mscx-ad-sponsor feign & hystrix get user error."); } }
In the ISponsorFeignClient class, add the fallback class
@FeignClient(value = "mscx-ad-sponsor", fallback = SponsorClientHystrix.class) public interface ISponsorFeignClient { ...
In the ponsorClientHystrix, we need to pay special attention to two points
- This class must have the @Component annotation added so that it can be added to the Spring container
- This class needs to implement the client interface of ISponsorFeignClientFeign
With the above implementation, our service will be downgraded if an error occurs during the invocation process, and the method in the default processing class that should be invoked if an error occurs will be invoked, which also implements the short-circuit processing we want to do to protect our current service.