之前几章演示的熔断,降级 都是 RestTemplate + Ribbon 和 RestTemplate + Hystrix ,但是在实际开发并不是这样,实际开发中都是 Feign 远程接口调用。
Feign + Hystrix 演示:
eruka(略)
order 服务工程:
pom.xml
4.0.0
com.tuling.cloud
microservice-consumer-order-feign-hystrix-fallback
0.0.1-SNAPSHOT
jar
07-ms-consumer-order-feign-hystrix-fallback
org.springframework.boot
spring-boot-starter-parent
1.5.9.RELEASE
UTF-8
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-openfeign
org.springframework.cloud
spring-cloud-dependencies
Edgware.RELEASE
pom
import
org.springframework.boot
spring-boot-maven-plugin
ConsumerOrderApplication_07 启动类
package com.jiagoushi.cloud.study;
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;
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients // feign-hystrix 支持, 不用在写@EnableCircuitBreaker
public class ConsumerOrderApplication_07 {
public static void main(String[] args) {
SpringApplication.run(ConsumerOrderApplication_07.class, args);
}
}
UserFeignClient接口:
package com.jiagoushi.cloud.study.user.feign;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.jiagoushi.cloud.study.user.entity.User;
/**
* Feign的fallback测试
* 使用@FeignClient的fallback属性指定回退类
*/
@FeignClient(name = "microservice-provider-user", fallback = FeignClientFallback.class /*, configuration = FeignDisableHystrixConfiguration.class 指定该类来设置禁用该接口的Hystrix*/)
public interface UserFeignClient {
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public User findById(@PathVariable("id") Long id);
}
/**
* 降级方法 FeignClientFallback 需实现Feign Client接口
* FeignClientFallback也可以是class,没有区别
* 不是每个接口都必须要有降级的。重要的方法才会有
*/
@Component
class FeignClientFallback implements UserFeignClient {
@Override
public User findById(Long id) {
User user = new User();
user.setId(-1L);
user.setUsername("降级用户");
return user;
}
}
-
feign注解 configuration = FeignDisableHystrixConfiguration.class 标识该feign接口禁用Hystrix
FeignDisableHystrixConfiguration类:
package com.jiagoushi.cloud.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import feign.Feign;
/**
注意:该类不能被启动扫描到。不然就是全局设置。
* 为Feign禁用Hystrix功能的配置类,可单独用在具体的Feign接口上
* 为什么要禁用? 因为Hystrix在接口上做了很多封装,限制接口线程池10个,有熔断,降级等功能,
* 有的接口不需要这么多功能所以要禁用
*/
@Configuration
public class FeignDisableHystrixConfiguration {
FeignDisableHystrixConfiguration(){
}
@Bean
@Scope("prototype")
public Feign.Builder feignBuilder() {
return Feign.builder();
}
}
applcation.yml:
server:
port: 9010
spring:
application:
name: microservice-consumer-order
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
# 开启feign支持hystrix,
# https://blog.csdn.net/mxmxz/article/details/84633098 这个链接关于feign+hystrix超时时间设置
# http://blog.java1234.com/blog/articles/440.html 这个链接关于feign+hystrix超时时间设置
feign:
hystrix:
enabled: true
#配置这个是无效的,因为feign 也有一个超时时间的设置,
#当然feign底层是 ribbon的封装,所以 直接配置ribbon,ribbon默认超时也是1秒。
#所以这里都是强制要求,ribbon的超时时间要大于hystrix的超时时间,
#否则 hystrix自定义的超时时间毫无意义。所以还得加个 ribbon超时时间设置
#hystrix:
# command:
# default:
# execution:
# isolation:
# thread:
# timeoutInMilliseconds: 3000
ribbon:
ReadTimeout: 10000
ConnectTimeout: 10000
# 解释一下:这种配置会出现这样的现象:
# order服务Feign调用user服务时,因为user睡眠4S,所以浏览器会一直转4s等待,这种情况只会等待三次,之后仍然继续
# 调用user服务时,Feign 直接降级,浏览器转的时间很短。说明被降级了服务器响应快。
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000 #feign整合hystrix 光设置Hystrix 超时没用的要配合ribbon超时
circuitBreaker:
requestVolumeThreshold: 3 #默认20 ,熔断的阈值,如何user服务报错满足3次,熔断器就会打开,就算order之后请求正确的数据也不行。
sleepWindowInMilliseconds: 8000 #默认5S , 等5S之后熔断器会处于半开状态,然后下一次请求的正确和错误讲决定熔断器是否真的关闭和是否继续打开
# 说明:请务必注意,从Spring Cloud Dalston开始,Feign默认是不开启Hystrix的。
# 因此,如使用Dalston请务必额外设置属性:feign.hystrix.enabled=true,否则断路器不会生效。
# 而,Spring Cloud Angel/Brixton/Camden中,Feign默认都是开启Hystrix的。无需设置该属性。
user服务工程:
pom.xml:
4.0.0
com.tuling.cloud
microservice-provider-user
0.0.1-SNAPSHOT
jar
07-provider-user
org.springframework.boot
spring-boot-starter-parent
1.5.9.RELEASE
UTF-8
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-jpa
com.h2database
h2
org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-dependencies
Edgware.RELEASE
pom
import
org.springframework.boot
spring-boot-maven-plugin
application.yml:
server:
port: 8010
spring:
application:
name: microservice-provider-user
jpa:
generate-ddl: false
show-sql: true
hibernate:
ddl-auto: none
datasource: # 指定数据源
platform: h2 # 指定数据源类型
schema: classpath:schema.sql # 指定h2数据库的建表脚本
data: classpath:data.sql # 指定h2数据库的数据脚本
logging: # 配置日志级别,让hibernate打印出执行的SQL
level:
root: INFO
org.hibernate: INFO
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
org.hibernate.type.descriptor.sql.BasicExtractor: TRACE
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
UserComtroller:
package com.tuling.cloud.study.controller;
import java.util.Random;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import com.tuling.cloud.study.entity.User;
import com.tuling.cloud.study.repository.UserRepository;
@RestController
public class UserController {
private final Logger logger = Logger.getLogger(getClass());
@Autowired
private UserRepository userRepository;
@Autowired
private Registration registration;
@GetMapping("/{id}")
public User findById(@PathVariable Long id) throws Exception {
// 模拟hystrix 超时降级
Thread.sleep(4000);
//测试熔断,传入不存在的用户id模拟异常情况
/* if (id == 10) {
throw new NullPointerException();
}*/
logger.info("用户中心接口:查询用户"+ id +"信息");
User findOne = userRepository.findOne(id);
return findOne;
}
@GetMapping("/getIpAndPort")
public String findById() {
return registration.getHost() + ":" + registration.getPort();
}
}
ProviderUserApplication类:
package com.tuling.cloud.study;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class ProviderUserApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderUserApplication.class, args);
}
}
当user服务sleep(4000) 效果图:
测试Hystrix 阈值设置3时把注释去掉: