从零开始学spring cloud(十) -------- hystrix简单代码示例

时间:2023-01-18 07:57:28

一、官网文档阅读

从零开始学spring cloud(十) -------- hystrix简单代码示例

较低级别的服务中的服务故障可能导致级联故障一直到用户。 当对特定服务的调用超过circuitBreaker.requestVolumeThreshold(默认值:20个请求)且失败百分比大于circuit.rolllingStats.timeInMilliseconds定义的滚动窗口中的circuitBreaker.errorThresholdPercentage(默认值:> 50%)时(默认值:10秒) ,电路打开,没有拨打电话。 在出现错误和开路的情况下,开发人员可以提供回退。

二、示例

添加hystrix依赖

        <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

修改movie服务的controller

 package com.zwjk.cloud.controller;

 import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.zwjk.cloud.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate; /**
* @author : Jixiaohu
* @Date : 2019-04-11.
* @Time : 9:38.
* @Description :
*/
@RestController
public class MovieController { @Autowired
private RestTemplate restTemplate; @Value("${user.userServicePath}")
private String userServicePath; @GetMapping("/movie/{id}")
@HystrixCommand(fallbackMethod = "findByIdFallback")
public User findById(@PathVariable Long id) {
return this.restTemplate.getForObject(this.userServicePath + id, User.class);
} public User findByIdFallback(Long id) {
User user = new User();
user.setId(0L);
user.setName("失败");
return user;
}
}

这边需要注意的是,fallbackMethod方法的返回值和入参,必须和原方法一致,下面进行测试:

从零开始学spring cloud(十) -------- hystrix简单代码示例

可以看到,这里返回了正常的结果,下面停掉user服务

从零开始学spring cloud(十) -------- hystrix简单代码示例

可以看到,这里返回的结果,就是fallbackMethod里面返回的内容,hystrix就起了作用。

下面,继续看一下

Feign Hystrix Support

参考官网使用示例:

 @FeignClient(name = "hello", fallback = HystrixClientFallback.class)
protected interface HystrixClient {
@RequestMapping(method = RequestMethod.GET, value = "/hello")
Hello iFailSometimes();
} static class HystrixClientFallback implements HystrixClient {
@Override
public Hello iFailSometimes() {
return new Hello("fallback");
}
}

在配置文件中,增加开启feign使用断路器

feign:
hystrix:
enabled: true

按照示例,我们在movie服务中,新增UserFeignClientFallback类

 package com.zwjk.cloud.fegin;

 import com.zwjk.cloud.entity.User;
import org.springframework.stereotype.Component; /**
* @author : Jixiaohu
* @Date : 2019-04-17.
* @Time : 18:20.
* @Description :
*/
@Component
public class UserFeignClientFallback implements UserFeignClient {
@Override
public User findById(Long id) {
User user = new User();
user.setId(0L);
return user;
}
}

在fegin上增加相应的注解:

 package com.zwjk.cloud.fegin;

 import com.zwjk.cloud.entity.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; /**
* @author : Jixiaohu
* @Date : 2019-04-12.
* @Time : 16:50.
* @Description :
*/
@FeignClient(name = "microservice-provider-user", fallback = UserFeignClientFallback.class)
public interface UserFeignClient {
//@PathVariable得设置value
@GetMapping("/simple/{id}")
User findById(@PathVariable("id") Long id); //@PathVariable得设置value
}

启动项目,进行测试,

从零开始学spring cloud(十) -------- hystrix简单代码示例

同样的,停掉user服务,再次访问这个地址:

从零开始学spring cloud(十) -------- hystrix简单代码示例

就可以实现熔断服务

当一个项目中,有个feign时,如何禁用一些feign的hystrix?

查看一下官网文档

从零开始学spring cloud(十) -------- hystrix简单代码示例

通过配置加上feignBuilder,就可以禁用指定fegin的hystrix

查看一下代码实现:

 package com.zwjk.cloud.controller;

 import com.zwjk.cloud.entity.User;
import com.zwjk.cloud.fegin.UserFeignClient2;
import com.zwjk.cloud.fegin.UserFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController; /**
* @author : Jixiaohu
* @Date : 2019-04-11.
* @Time : 9:38.
* @Description :
*/
@RestController
public class MovieController { @Autowired
private UserFeignClient userFeignClient; @Autowired
private UserFeignClient2 userFeignClient2; @GetMapping("/movie/{id}")
public User findById(@PathVariable Long id) {
return this.userFeignClient.findById(id);
} @GetMapping("/{serviceName}")
public String findServiceInfoFromEurekaByServiceName(@PathVariable String serviceName) {
return this.userFeignClient2.findServiceInfoFromEurekaByServiceName(serviceName);
} }

两个fegin:

 package com.zwjk.cloud.fegin;

 import com.zwjk.cloud.entity.User;
import com.zwjk.config.UserConfiguration;
import feign.Param;
import feign.RequestLine;
import org.springframework.cloud.openfeign.FeignClient; /**
* @author : Jixiaohu
* @Date : 2019-04-12.
* @Time : 16:50.
* @Description :
*/
@FeignClient(name = "microservice-provider-user", configuration = UserConfiguration.class, fallback =
UserFeignClientFallback.class)
public interface UserFeignClient {
//@PathVariable得设置value
@RequestLine("GET /simple/{id}")
User findById(@Param("id") Long id); //@PathVariable得设置value }
 package com.zwjk.cloud.fegin;

 import com.zwjk.config.UserConfiguration2;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; /**
* @author : Jixiaohu
* @Date : 2019-04-13.
* @Time : 11:23.
* @Description :
*/
@FeignClient(name = "xxxx", url = "http://192.168.1.114:8761/", configuration = UserConfiguration2.class)
public interface UserFeignClient2 {
@RequestMapping(value = "/eureka/apps/{serviceName}")
public String findServiceInfoFromEurekaByServiceName(@PathVariable("serviceName") String serviceName);
}

两个fallback

 package com.zwjk.cloud.fegin;

 import org.springframework.stereotype.Component;

 /**
* @author : Jixiaohu
* @Date : 2019-04-17.
* @Time : 18:20.
* @Description :
*/
@Component
public class UserFeignClient2Fallback implements UserFeignClient2 { @Override
public String findServiceInfoFromEurekaByServiceName(String serviceName) {
return "hahahha";
}
}
 package com.zwjk.cloud.fegin;

 import com.zwjk.cloud.entity.User;
import org.springframework.stereotype.Component; /**
* @author : Jixiaohu
* @Date : 2019-04-17.
* @Time : 18:20.
* @Description :
*/
@Component
public class UserFeignClientFallback implements UserFeignClient {
@Override
public User findById(Long id) {
User user = new User();
user.setId(0L);
return user;
}
}

看一下两个配置文件

 package com.zwjk.config;

 import feign.Contract;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; /**
* @author : Jixiaohu
* @Date : 2019-04-13.
* @Time : 10:20.
* @Description :
*/
@Configuration
public class UserConfiguration { @Bean
public Contract feignContract() {
return new feign.Contract.Default();
} @Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
 package com.zwjk.config;

 import feign.Feign;
import feign.auth.BasicAuthRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope; /**
* @author : Jixiaohu
* @Date : 2019-04-13.
* @Time : 11:25.
* @Description :
*/
@Configuration
public class UserConfiguration2 {
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("user", "password123");
} @Configuration
public class FooConfiguration {
@Bean
@Scope("prototype")
public Feign.Builder feignBuilder() {
return Feign.builder();
}
}
}

启动服务,进行测试

从零开始学spring cloud(十) -------- hystrix简单代码示例

从零开始学spring cloud(十) -------- hystrix简单代码示例

下面,我们停掉eureka,和user服务,在一次查看返回结果

启用hystrix的返回结果如下:

从零开始学spring cloud(十) -------- hystrix简单代码示例

没有启用hystrix的返回结果,提示500错误

从零开始学spring cloud(十) -------- hystrix简单代码示例

从中,可以看出,hytrix的熔断,可以有很细的粒度。

如果想要查看fallback回退的原因,可以使用可以使用@FeignClient中的fallbackFactory属性。

看一下如何实现?

参考一下官网文档:

从零开始学spring cloud(十) -------- hystrix简单代码示例

先写一个hystrixFactory:

 package com.zwjk.cloud.fegin;

 import com.zwjk.cloud.entity.User;
import feign.hystrix.FallbackFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component; /**
* @author : Jixiaohu
* @Date : 2019-04-17.
* @Time : 19:37.
* @Description :
*/
@Component
public class UserFeginClientFactory implements FallbackFactory<UserFeignClient> { private static final Logger Log = LoggerFactory.getLogger(UserFeginClientFactory.class); @Override
public UserFeignClient create(Throwable cause) {
UserFeginClientFactory.Log.info("fallback:reason was : {}", cause.getMessage());
return id -> {
User user = new User();
user.setId(-1L);
user.setName("haha");
return user;
};
}
}

修改一下原feignClient

 package com.zwjk.cloud.fegin;

 import com.zwjk.cloud.entity.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; /**
* @author : Jixiaohu
* @Date : 2019-04-12.
* @Time : 16:50.
* @Description :
*/
@FeignClient(name = "microservice-provider-user", fallbackFactory =
UserFeginClientFactory.class)
public interface UserFeignClient {
//@PathVariable得设置value
@GetMapping("/simple/{id}")
User findById(@PathVariable("id") Long id); //@PathVariable得设置value
}

启动user服务,movie服务,先正常访问:

然后关闭user服务,会发现控制台开始打印日志:

从零开始学spring cloud(十) -------- hystrix简单代码示例

这是为什么呢?因为此时,断路器并没有打开,实际的原因是TimeoutException

从零开始学spring cloud(十) -------- hystrix简单代码示例

当断路器打开时,就会答应异常的信息。