SpringCloud之Feign组合Hystrix降级入门案例

基础

https://blog.csdn.net/qq_41520636/article/details/115668271

Hystrix 降级

Hystix 降级:当服务发生异常或调用超时,返回默认数据

项目结构

 hystrix-provider(服务提供方)

1、定义降级方法

2、使用 @HystrixCommand 注解配置降级方法

3、在启动类上开启Hystrix功能:@EnableCircuitBreaker

pom

<?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>spring-cloud-parent</artifactId>
        <groupId>com.hikktn</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    
    <artifactId>hystrix-provider</artifactId>
    <dependencies>
        
        <!--spring boot 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>
        
        <!-- eureka-client -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        
        <!-- hystrix -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
    
    </dependencies>

</project>

 application.yml

server:
  port: 8001

eureka:
  instance:
    hostname: localhost # 主机名
    prefer-ip-address: true # 将当前实例的ip注册到eureka server 中。默认是false 注册主机名
    ip-address: 127.0.0.1 # 设置当前实例的ip
    instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port} # 设置web控制台显示的 实例id
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
spring:
  application:
    name: hystrix-provider # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径

bean

package com.hikktn.entity;

import java.io.Serializable;

/**
 * @ClassName Response
 * @Description TODO
 * @Author lisonglin
 * @Date 2021/4/16 13:20
 * @Version 1.0
 */
public class AbstractResult<T> implements Serializable {
	private int id;
	private int code;
	private String error;
	private T data;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public int getCode() {
		return code;
	}

	public void setCode(int code) {
		this.code = code;
	}

	public String getError() {
		return error;
	}

	public void setError(String error) {
		this.error = error;
	}

	public T getData() {
		return data;
	}

	public void setData(T data) {
		this.data = data;
	}

	public AbstractResult() {
	}

	public AbstractResult(int id, int code, String error, T data) {
		this.id = id;
		this.code = code;
		this.error = error;
		this.data = data;
	}

	@Override
	public String toString() {
		return "AbstractResult{" + "id=" + id + ", code=" + code + ", error='" + error + '\'' + ", data=" + data + '}';
	}
}
package com.hikktn.entity;

import java.io.Serializable;

/**
 * @ClassName Goods
 * @Description 商品实体类
 * @Author lisonglin
 * @Date 2021/4/12 14:40
 * @Version 1.0
 */
public class Goods implements Serializable {
	private int id;
	// 商品标题
	private String title;
	// 商品价格
	private double price;
	// 商品库存
	private int count;

	public Goods() {
	}

	public Goods(int id, String title, double price, int count) {
		this.id = id;
		this.title = title;
		this.price = price;
		this.count = count;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public int getCount() {
		return count;
	}

	public void setCount(int count) {
		this.count = count;
	}

	@Override
	public String toString() {
		return "Goods{" + "id=" + id + ", title='" + title + '\'' + ", price=" + price + ", count=" + count + '}';
	}
}

 dao

package com.hikktn.dao;

import com.hikktn.entity.Goods;
import org.springframework.stereotype.Repository;

/**
 * @ClassName GoodsDao
 * @Description TODO
 * @Author lisonglin
 * @Date 2021/4/12 14:42
 * @Version 1.0
 */
@Repository
public class GoodsDao {

	public Goods findOne(int id){
		// 这里是从数据库中查询得出
		return new Goods(1,"小米手机",1999.0,50);
	}
}

service

package com.hikktn.service;

import com.hikktn.dao.GoodsDao;
import com.hikktn.entity.Goods;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @ClassName GoodsService
 * @Description TODO
 * @Author lisonglin
 * @Date 2021/4/12 14:44
 * @Version 1.0
 */
@Service
public class GoodsService {
	@Autowired
	private GoodsDao goodsDao;

	public Goods findOne(int id){
		return goodsDao.findOne(id);
	}
}

 控制器

package com.hikktn.controller;

import com.hikktn.entity.AbstractResult;
import com.hikktn.entity.Goods;
import com.hikktn.service.GoodsService;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @ClassName GoodsController
 * @Description 服务的提供方
 * @Author lisonglin
 * @Date 2021/4/12 14:45
 * @Version 1.0
 */
@RestController
@RequestMapping("/goods")
public class GoodsController {
	@Autowired
	private GoodsService goodsService;

	@Value("${server.port}")
	private int port;

	@GetMapping("/findOne/{id}")
	@HystrixCommand(fallbackMethod = "defaultFallback",commandProperties = {
			//设置Hystrix的超时时间,默认1s
			@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000")
	})
	public AbstractResult<Goods> findOne(@PathVariable("id") int id){

		Goods goods = goodsService.findOne(id);

		//1.造个异常
		// int i = 3/0;
		// //当前线程睡2秒
		// try {
		// 	Thread.sleep(2000);
		// } catch (InterruptedException e) {
		// 	e.printStackTrace();
		// }
		goods.setTitle(goods.getTitle() + ":" + port);//将端口号,设置到了 商品标题上
		AbstractResult<Goods> result = new AbstractResult<Goods>(1, 200, "服务端正常访问", goods);
		return result;
	}

	/**
	 * 定义降级方法:
	 *  1. 方法的返回值需要和原方法一样
	 *  2. 方法的参数需要和原方法一样
	 */
	public AbstractResult<Goods> defaultFallback(@PathVariable("id") int id){
		AbstractResult<Goods> result = new AbstractResult<Goods>(id, 500, "服务端降级了~~~", null);
		return result;
	}
}

启动类 

package com.hikktn;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * @ClassName ProviderApp
 * @Description TODO
 * @Author lisonglin
 * @Date 2021/4/12 14:37
 * @Version 1.0
 */
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker // 开启Hystrix功能
public class HystrixProviderApp {

	public static void main(String[] args){
		SpringApplication.run(HystrixProviderApp.class,args);
	}

}

 测试

正常情况

降级情况

将GoodsController.java类中的

放开

hystrix-consumer(服务消费方)

1、定义feign调用接口实现类,复写方法,此方法为降级方法。

2、在@FeignClient 注解中使用 fallback 属性设置降级处理类。

3、配置开启 feign.hystrix.enabled = true

pom

<?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>spring-cloud-parent</artifactId>
        <groupId>com.hikktn</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    
    <artifactId>hystrix-consumer</artifactId>
    <dependencies>
        
        <!--spring boot 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>
        
        <!-- eureka-client -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        
        <!--feign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>

</project>

application.yml

server:
  port: 9000

eureka:
  instance:
    hostname: localhost # 主机名
    # 是否将自己的ip注册到eureka中
    prefer-ip-address: true
    # 设置当前实例ip
    ip-address: 127.0.0.1
    # 设置web控制台显示的实例id
    instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port}:@project.version@
  client:
    service-url:
      # eureka 服务端地址,客户端使用该地址和enreka创建连接
      defaultZone: http://localhost:8761/eureka

spring:
  application:
    name: hystrix-consumer # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径

# 开启feign对hystrix的支持
feign:
  hystrix:
    enabled: true


# 配置的方式设置Ribbon的负载均衡策略
HYSTRIX-PROVIDER: # 设置的服务提供方的 应用名称
  ribbon:
    NFloadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 策略类
    ConnectTimeout: 1000 # 连接超时时间 默认1s
    ReadTimeout: 3000 # 逻辑处理的超时时间 默认1s

# 设置当前的日志级别 debug,feign只支持记录debug级别的日志
logging:
  level:
    com.hikktn: debug

配置类

package com.hikktn.config;

import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignLogConfig {


    /*
        NONE,不记录
        BASIC,记录基本的请求行,响应状态码数据
        HEADERS,记录基本的请求行,响应状态码数据,记录响应头信息
        FULL;记录完成的请求 响应数据
     */

    @Bean
    public Logger.Level level(){
        return Logger.Level.FULL;
    }
}

bean

package com.hikktn.entity;

import java.io.Serializable;

/**
 * @ClassName Response
 * @Description TODO
 * @Author lisonglin
 * @Date 2021/4/16 13:20
 * @Version 1.0
 */
public class AbstractResult<T> implements Serializable {
	private int id;
	private int code;
	private String error;
	private T data;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public int getCode() {
		return code;
	}

	public void setCode(int code) {
		this.code = code;
	}

	public String getError() {
		return error;
	}

	public void setError(String error) {
		this.error = error;
	}

	public AbstractResult(int id, int code, String error, T data) {
		this.id = id;
		this.code = code;
		this.error = error;
		this.data = data;
	}

	public AbstractResult() {
	}

	public T getData() {
		return data;
	}

	public void setData(T data) {
		this.data = data;
	}

	@Override
	public String toString() {
		return "AbstractResult{" + "id=" + id + ", code=" + code + ", error='" + error + '\'' + ", data=" + data + '}';
	}
}
package com.hikktn.entity;

import java.io.Serializable;

/**
 * @ClassName Goods
 * @Description 商品实体类
 * @Author lisonglin
 * @Date 2021/4/12 14:40
 * @Version 1.0
 */
public class Goods implements Serializable {
	private int id;
	// 商品标题
	private String title;
	// 商品价格
	private double price;
	// 商品库存
	private int count;

	public Goods() {
	}

	public Goods(int id, String title, double price, int count) {
		this.id = id;
		this.title = title;
		this.price = price;
		this.count = count;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public int getCount() {
		return count;
	}

	public void setCount(int count) {
		this.count = count;
	}

	@Override
	public String toString() {
		return "Goods{" + "id=" + id + ", title='" + title + '\'' + ", price=" + price + ", count=" + count + '}';
	}
}

接口

package com.hikktn.service;

import com.hikktn.config.FeignLogConfig;
import com.hikktn.entity.AbstractResult;
import com.hikktn.entity.Goods;
import com.hikktn.service.impl.GoodsFeignImpl;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * @ClassName GoodsFeign
 * @Description TODO
 * @Author lisonglin
 * @Date 2021/4/16 1:54
 * @Version 1.0
 */
@FeignClient(value = "HYSTRIX-PROVIDER",configuration = FeignLogConfig.class,fallback = GoodsFeignImpl.class)
public interface GoodsFeign {

	@GetMapping("/goods/findOne/{id}")
	public AbstractResult<Goods> findGoodsById(@PathVariable("id") int id);
}

接口实现类

package com.hikktn.service.impl;

import com.hikktn.entity.AbstractResult;
import com.hikktn.entity.Goods;
import com.hikktn.service.GoodsFeign;
import org.springframework.stereotype.Component;

/**
 * @ClassName GoodsFeignImpl
 * @Description TODO
 * @Author lisonglin
 * @Date 2021/4/16 18:14
 * @Version 1.0
 */
@Component
public class GoodsFeignImpl implements GoodsFeign {
	@Override
	public AbstractResult<Goods> findGoodsById(int id) {
		AbstractResult result = new AbstractResult();
		result.setCode(500);
		result.setError("客户端降级了");
		return result;
	}
}

控制器

package com.hikktn.controller;

import com.hikktn.entity.AbstractResult;
import com.hikktn.entity.Goods;
import com.hikktn.service.GoodsFeign;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @ClassName OrderController
 * @Description 服务的消费方
 * @Author lisonglin
 * @Date 2021/4/12 14:51
 * @Version 1.0
 */
@RestController
@RequestMapping("/order")
public class OrderController {
	@Autowired
	private GoodsFeign goodsFeign;

	@GetMapping("/goods/{id}")
	public AbstractResult findOne(@PathVariable("id") int id) {
		AbstractResult<Goods> goods = goodsFeign.findGoodsById(id);
		System.out.println("结果:"+goods);
		return goods;
	}
}

启动类

package com.hikktn;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @ClassName ProviderApp
 * @Description TODO
 * @Author lisonglin
 * @Date 2021/4/12 14:37
 * @Version 1.0
 */
@SpringBootApplication
@EnableFeignClients //开启Feign的功能
public class HystrixConsumerApp {

	public static void main(String[] args){
		SpringApplication.run(HystrixConsumerApp.class,args);
	}

}

测试

启动三个项目

  • eureka-server
  • hystrix-consumer
  • hystrix-provider

正常情况

降级情况

将GoodsController.java类中的,因为在consumer中没有设置连接超时时间,而连接超时时间默认为1秒钟,所以当提供方等待两秒钟,消费方就已经出现错误,画面挂掉了,而后进行了降级处理。

放开

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hikktn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值