【Spring Cloud总结】20.Feign对Hystrix的支持

接上篇《19.Hystrix Health Indicator及Metrics Stream支持》  Spring Cloud版本为Finchley.SR2版

上一篇我们简单介绍了Hystrix的健康指数监控以及API监控,分别用来查看Hystrix断路器的状态,以及应用API服务的详细监控情况。本篇我们来讲解如何在Feign组件中使用Hystrix。
本部分官方文档:https://cloud.spring.io/spring-cloud-static/Finchley.SR2/single/spring-cloud.html

一、回顾Feign组件

之前我们讲过,Feign组件是用来实现声明式服务调用功能的,换句话说就是Feign可以优雅的调用REST风格的服务。我们回顾一下之前的Feign组件的使用过程:
首先我们在Movie工程的Controller中通过userFeignClient接口对象,去调用findById方法,而此方法就是通过Feign组件进行远程REST服务的调用:

@Autowired
private UserFeignClient userFeignClient;

@GetMapping("/movie/{id}")
@HystrixCommand(fallbackMethod = "findUserByIdFallback",
    commandProperties = {@HystrixProperty(name="execution.isolation.strategy",value="SEMAPHORE")})
public User findUserById(@PathVariable Long id){
    return userFeignClient.findById(id);
}

public User findUserByIdFallback(Long id){
    User user = new User();
    user.setId(0L);
    return user;
}

这里UserFeignClient接口就封装了Feign组件的实现:

package com.microserver.cloud;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import com.microserver.cloud.entity.User;
import com.microserver.config.TestFeignConfiguration;
import feign.Param;
import feign.RequestLine;

@FeignClient(name="microserver-provider-user",configuration = TestFeignConfiguration.class )
public interface UserFeignClient {
    
    @RequestLine("GET /findById/{id}")
    public User findById(@Param("id") Long id);
    
    @RequestLine("POST /postUser")
    public String postUser(@RequestBody User user);
}

这里我们在接口头部仅需要定义@FeignClient,以及要调用的远程服务的实例名,配置类信息即可。在每个方法定义上,添加@RequestLine注解,来定义该服务的请求类型以及实际请求URL。
这样实现了一个Feign组件调用远程服务的效果。

在上面的例子中,我们加入Hystrix实现断路器的方式是,在调用userFeignClient之前的Controller方法中添加@HystrixCommand以及降级方法fallbackMethod,其实如果我们要单纯的处理findById方法的断路降级问题,直接在UserFeignClient接口中,即在Feign组件中实现Hystrix断路器即可。

下面我们在Feign中实现Hystrix断路器。

二、在Feign组件中使用Hystrix

Spring Cloud默认已为Feign整合了Hystrix,只要Hystrix在项目的classpath中,Feign默认就会用断路器包裹所有方法。
如果要使用Feign的Hystrix支持,可以设置feign.hystrix.enabled=true,要禁用,设置为false即可。

我们可以通过以下方式来实现Feign的Hystrix支持:
1、@FeignClient注解配置fallback参数,实现FeignClient接口
我们可以在之前的FeignClient接口上的@FeignClient添加fallback参数,该参数是一个FeignClient接口的实现类,在实现类中实现FeignClient接口中的各个方法即可。
当FeignClient接口中的服务调用失败,触发断路器打开,请求转移的降级服务,就是FeignClient接口实现类中的同名方法。

我们来实现这个效果。首先在Movie工程的application.yml配置文件中开启Feign的Hystrix支持:

feign:
  hystrix:
    enabled: true

然后修改一下之前的Controller类以及UserFeignClient接口,使其实现Feign对Hystrix的支持:

@Autowired
private UserFeignClient userFeignClient;

@GetMapping("/movie/{id}")
public User findUserById(@PathVariable Long id){
    return userFeignClient.findById(id);
}

UserFeignClient接口:

package com.microserver.cloud;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;
import com.microserver.cloud.entity.User;
import com.microserver.config.TestFeignConfiguration;
import feign.Param;
import feign.RequestLine;

@FeignClient(name="microserver-provider-user",configuration = TestFeignConfiguration.class,
    fallback = FeignClientFallback.class )
public interface UserFeignClient {

    @RequestLine("GET /findById/{id}")
    public User findById(@Param("id") Long id);
    
    @RequestLine("POST /postUser")
    public String postUser(@RequestBody User user);
}

@Component
class FeignClientFallback implements UserFeignClient{

    @Override
    public User findById(Long id) {
        User user = new User();
        user.setId(0L);
        user.setName("FeignClient 降级服务");
        return user;
    }

    @Override
    public String postUser(User user) {
        return null;
    }
    
}

可以看到,我们在fallback中定义了降级实现类FeignClientFallback,然后编写了该内部类,实现了UserFeignClient接口,然后实现接口中的每一个方法,定义降级服务的内容,其中findById的内容,和之前在Controller中的“findUserByIdFallback”方法内容相同,这里我们将默认的user对象的name定义为“FeignClient 降级服务”,为了测试证明该服务是Feign组件触发的。

这里我们启动之前的服务提供者user工程、服务消费者movie工程以及eureka Server注册中心,访问“movie/1”服务是好的:

然后关掉服务提供者user工程,再次访问“movie/1”服务,可以看到此时进入了降级服务中:

打印的name内容就是之前降级服务中定义的内容,证明我们通过Feign调用Hystrix成功!


2、@FeignClient注解配置fallbackFactory参数,实现FallbackFactory接口
fallbackFactory参数指定一个fallback工厂,与指定fallback不同, 此工厂可以用来获取到触发断路器的异常信息,fallback工厂类需要实现FallbackFactory类。我们修改一下之前的UserFeignClient,来实现FallbackFactory的断路效果:

package com.microserver.cloud;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;
import com.microserver.cloud.entity.User;
import com.microserver.config.TestFeignConfiguration;
import feign.Param;
import feign.RequestLine;
import feign.hystrix.FallbackFactory;

@FeignClient(name="microserver-provider-user",configuration = TestFeignConfiguration.class,/*fallback = FeignClientFallback.class*/
    fallbackFactory=FeignClientFallbackFactory.class)
public interface UserFeignClient {
    
    @RequestLine("GET /findById/{id}")
    public User findById(@Param("id") Long id);
    
    @RequestLine("POST /postUser")
    public String postUser(@RequestBody User user);
}

@Component
class FeignClientFallbackFactory implements FallbackFactory<UserFeignClient>{

    //日志对象
    private static final Logger LOGGER = LoggerFactory.getLogger(FeignClientFallbackFactory.class);

    @Override
    public UserFeignClient create(Throwable cause) {
        return new UserFeignClient() {
            
            @Override
            public User findById(Long id) {
                // 日志最好放在各个fallback方法中,而不要直接放在create方法中。
                // 否则在引用启动时,就会打印该日志
                FeignClientFallbackFactory.LOGGER.info("fallback; reason was: ", cause);
                
                User user = new User();
                user.setId(0L);
                user.setName("FeignClient 降级服务");
                return user;
            }

            @Override
            public String postUser(User user) {
                return null;
            }
        };
    }
}

可以看到,我们指定的fallbackFactory参数对应的内部类,实现了FallbackFactory<T>接口,泛型中的T即是我们的UserFeignClient接口。FallbackFactory<T>接口需要实现一个create方法,该方法引入了异常Throwable对象作为参数,在Hystrix断路器启动后,触发降级请求,此时create方法会返回一个定义了所有方法降级服务的UserFeignClient类,并且在Throwable对象中包装了具体的异常信息,我们可以将异常信息打印到控制台。

我们按照之前的方式,只启动服务消费者movie工程和eureka Server注册中心,不启动服务提供者user工程,此时访问“movie/1”服务:

然后我们在编译器的控制台可以看到:

说明请求不仅进入了降级服务,而且打印出了详细的异常信息,这里的异常主要是microserver-provider-user服务不可用,其实是我们的服务提供者没有启动造成的。

总的来说,fallback工厂类的优点是可以通过Throwable对象获取到异常信息。

至此,Feign对支持Hystrix支持相关的知识就介绍到这里了。


参考:《51CTO学院Spring Cloud高级视频》

转载请注明出处:https://blog.csdn.net/acmman/article/details/101864536

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章