cloud-provider-hystrix-payment8001模拟支付模块
依赖:
<?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>cloud2020</artifactId>
<groupId>pers.zhang.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-provider-hystrix-payment8001</artifactId>
<dependencies>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<groupId>pers.zhang.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
配置:application.yml
server:
port: 8001
spring:
application:
name: cloud-provider-hystrix-payment
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka
#defaultZone: http://eureka7001.com:7001/eureka,http://wureka7002.com:7002/eureka
Service:
@Service
public class PaymentService {
/**
* 正常访问,肯定OK
* @param id
* @return
*/
public String paymentInfo_OK(Integer id) {
return "线程池:" + Thread.currentThread().getName() + " paymentInfo_OK, id:" + id;
}
/**
* 超时错误
* @param id
* @return
*/
@HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000")
})//指定超时回调,时间为2秒
public String paymentInfo_TimeOut(Integer id) {
//int a = 10 / 0;
try {//睡3秒,模拟超时
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "线程池:" + Thread.currentThread().getName() + " paymentInfo_TimeOut, id:" + id;
}
public String paymentInfo_TimeOutHandler(Integer id) {
return "线程池:" + Thread.currentThread().getName() + " 系统繁忙,请稍后再试, id:" + id + "超时回调";
}
}
Controller:
@RestController
@Slf4j
public class PaymentController {
@Resource
PaymentService paymentService;
@Value("${server.port}")
String serverPort;
@GetMapping("/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id) {
String result = paymentService.paymentInfo_OK(id);
log.info("*****result:" + result);
return result;
}
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
String result = paymentService.paymentInfo_TimeOut(id);
log.info("*****result:" + result);
return result;
}
}
启动类:
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker//开启
public class PaymentHystrixMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentHystrixMain8001.class, args);
}
}
cloud-consumer-feign-hystrix-order80模拟订单模块
依赖:
<?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>cloud2020</artifactId>
<groupId>pers.zhang.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-consumer-feign-hystrix-order80</artifactId>
<dependencies>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>pers.zhang.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--一般基础通用配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
配置:application.yml
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
feign:
hystrix:
enabled: true #开启hystrix
Service:
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT")//指定调用的服务名
public interface PaymentHystrixService {
@GetMapping("/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id);
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_TimeOut(@PathVariable("id") Integer id);
}
Controller:
@RestController
@Slf4j
public class OrderHystrixController {
@Resource
PaymentHystrixService paymentHystrixService;
@GetMapping("/consumer/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id) {
String result = paymentHystrixService.paymentInfo_OK(id);
return result;
}
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
@HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")//超时1.5秒
})
public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
String result = paymentHystrixService.paymentInfo_TimeOut(id);
return result;
}
public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
return "我是消费者80,对方支付系统繁忙,请10秒后再试或者自己运行出错请检查自己。";
}
}
启动类:
@SpringBootApplication
@EnableFeignClients
@EnableHystrix//开启Hystrix
public class OrderHystrixMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderHystrixMain80.class, args);
}
}
测试
我们在服务的提供方和消费方都使用了Hystrix,但是多数情况下只在消费方配置Hystrix。
启动Eureka,在启动支付和订单微服务。
先在8001端口进行本地测试:
访问:localhost:8001/payment/hystrix/ok/35
,成功
访问:localhost:8001/payment/hystrix/timeout/33
,失败,程序中睡眠3秒,触发Hystrix设置的2秒时限,服务降级,调用fallback方法:
通过80端口使用Feign调用8001:
访问:localhost/consumer/payment/hystrix/ok/22
:成功:
访问:localhost/consumer/payment/hystrix/timeout/11
:失败,订单模块作为消费方做出的超时限制为1.5秒,等待1.5秒无返回立即触发服务降级,调用fallback方法。
@DefaultProperties
每个方法都有一个fallback方法,为了避免代码膨胀,应该有一个同一的方法和自定义的fallback方法分开。
可以在类上加@Defaultproperties注解指定一个通用的fallback方法,凡是标注了@HystrixCommand但没有指定@HystrixProperty的方法,均使用@DefaultProperties指定的fallback方法。
修改80端口的Controller:
@RestController
@Slf4j
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public class OrderHystrixController {
@Resource
PaymentHystrixService paymentHystrixService;
@GetMapping("/consumer/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id) {
String result = paymentHystrixService.paymentInfo_OK(id);
return result;
}
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
//未指定fallback,使用@DefaultProperties指定的payment_Global_FallbackMethod
@HystrixCommand
// @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
// @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")//超时1.5秒
// })
public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
int a = 10 / 0;
String result = paymentHystrixService.paymentInfo_TimeOut(id);
return result;
}
public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
return "我是消费者80,对方支付系统繁忙,请10秒后再试或者自己运行出错请检查自己。";
}
//默认fallback
public String payment_Global_FallbackMethod() {
return "Global异常处理信息,请稍后再试...";
}
}
重启,访问:localhost/consumer/payment/hystrix/timeout/33
,失败,跳转到全局fallback:
fallback解耦
目前业务逻辑和fallback都混在一起,应该将两者分开。
只需要为Feign客户端定义的接口添加一个服务降级处理的实现 类即可实现解耦。
新建类PaymentFallbackService,实现PaymentHystrixService接口:
@Component
public class PaymentFallbackService implements PaymentHystrixService {
@Override
public String paymentInfo_OK(Integer id) {
return "-------PaymentFallbackService paymentInfo_OK fall back--------";
}
@Override
public String paymentInfo_TimeOut(Integer id) {
return "-------PaymentFallbackService paymentInfo_TimeOut fall back--------";
}
}
在@FeignClient中指明fallback处理类:
重启服务,访问:localhost/consumer/payment/hystrix/ok/55
,成功:
关闭8001服务,模拟宕机,再次访问:localhost/consumer/payment/hystrix/ok/55
:失败,执行PaymentFallbackService中对应的fallback方法