spring cloud的Hoxton.SR1版本的feign的优雅降级的实现

源码下载

在这里插入图片描述
大家可以直接微信扫描上面的二维码关注我的公众号,然后回复hoxton feign里面就会给到源代码的下载地址同时会附上相应的视频教程,并定期的与大家分享相关的技术文章。

前言

在我们基于spring cloud进行开发的时候我们的微服务之间的调用,会由于网络原因、程序原因、数据库等原因导致我们的微服务的调用失败,而失败则会导致抛出错误,这些错误就会不断往上抛,而给到用户很不好的体验,最简单粗暴的处理的方式就是调用其他微服务的时候我们直接try…catch起来直接进行处理,这种处理方式简单粗暴而且后期维护起来也是一个麻烦,因此我们需要一种更加优雅的处理方式,而feign刚好就为我们提供了这种优雅的处理方式,接下来我将为大家讲解如何优雅的实现我们的降级。

feign的优雅降级的实现

首先我们使用intellij开发工具创建一个空的项目,主要用于存放我们的整个工程,整个工程由以下三个项目组成,分别是:feign-demote-eureka【注册中心】、feign-demote-order【订单微服务】、feign-demote-account【账户微服务】。

注册中心

接着我们创建我们的注册中心工程feign-demote-eureka,创建完成以后修改我们的pom.xml修改完以后代码如下:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.cloud.feign.demote</groupId>
    <artifactId>feign-demote-eureka</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>feign-demote-eureka</name>
    <description>注册中心</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

接着修改我们的主入口类【FeignDemoteEurekaApplication.java】,将当前的工程配置为eureka的服务端,代码如下:

/**
 * @author linzf
 * @since 2019-12-26
 * 类描述: 注册中心的启动类
 */
@SpringBootApplication
@EnableEurekaServer
public class FeignDemoteEurekaApplication {

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

}

最后修改我们的application.yml配置文件,可能你创建的时候是application.properties,直接修改后缀为yml即可,修改以后代码如下:

server:
  port: 8761
spring:
  application:
    name: eureka-server
eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defultZone: http://${eureka.instance.hostname}:${server.port}/eureka/


这样我们就完成了我们注册中心的配置了,我们这时候可以直接启动我们的注册中心,然后访问:http://127.0.0.1:8761/就可以看到eureka的页面。

账户微服务

接着我们创建我们的账户微服务【feign-demote-account】,账户微服务没有任何特别的东西,只是提供了两个接口以及将自己注册到注册中心而已,因此我们只需要引入eureka的依赖即可,无需引入我们的feign的依赖,创建完成以后修改我们的pom.xml修改完以后代码如下:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.cloud.feign.demote</groupId>
    <artifactId>feign-demote-account</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>feign-demote-account</name>
    <description>账户模块</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

接着修改我们的主入口类【FeignDemoteAccountApplication.java】,将当前的工程配置为eureka的客户端,代码如下:

/**
 * @author linzf
 * @since 2019-12-26
 * 类描述: 账户的主入口类
 */
@SpringBootApplication
@EnableDiscoveryClient
public class FeignDemoteAccountApplication {

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

}

最后修改我们的application.yml配置文件,可能你创建的时候是application.properties,直接修改后缀为yml即可,修改以后代码如下:

eureka:
  instance:
    hostname: localhost
    prefer-ip-address: true
  client:
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:8761/eureka/

# 若将这个参数设置为false,将不会触发feign的降级处理
feign:
  hystrix:
    enabled: true

logging:
  level:
    root: INFO
    com:
      cloud:
        feign:
          demote:
            account: DEBUG

server:
  port: 8280
spring:
  application:
    name: account-server

ribbon:
  eureka:
    enabled: true
  ReadTimeout: 120000
  ConnectTimeout: 120000
  MaxAutoRetries: 0
  MaxAutoRetriesNextServer: 0
  OkToRetryOnAllOperations: false
  NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

# 设置断路器超时时间
hystrix:
  threadpool:
    default:
      coreSize: 1000
      maxQueueSize: 1000
      queueSizeRejectionThreshold: 500
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 490000
          strategy: SEMAPHORE

编写我们的【AccountService】的实现,一个方法是正常的方法【feignDemoteCheckSuccess】,另外一个方法是抛出异常的方法【feignDemoteCheckFail】,代码如下:

/**
 * @author linzf
 * @since 2019/12/26
 * 类描述:
 */
@Service
public class AccountService {

    private static Logger logger = LoggerFactory.getLogger(AccountService.class);

    /**
     * 功能描述: 正常的feign的调用
     * @return 返回处理结果
     */
    public String feignDemoteCheckSuccess(){
        logger.debug("我是正常的feign的调用!");
        return "success";
    }

    /**
     * 功能描述: 正常的feign的调用
     * @return 返回处理结果
     */
    public String feignDemoteCheckFail(){
        logger.debug("我调用的时候出错了!");
        throw new RuntimeException("我被抛出了异常了!");
    }

}

最后直接编写我们的接口【AccountController.java】的实现,单纯的接口的编写就不再累述了,直接贴代码:

/**
 * @author linzf
 * @since 2019/12/26
 * 类描述: 账户的controller
 */
@RestController
@RequestMapping(value = "account")
public class AccountController {

    @Autowired
    private AccountService accountService;

    /**
     * 功能描述: 正常的feign的调用
     * @return 返回处理结果
     */
    @GetMapping("feignDemoteCheckSuccess")
    public String feignDemoteCheckSuccess(){
        return accountService.feignDemoteCheckSuccess();
    }

    /**
     * 功能描述: 正常的feign的调用
     * @return 返回处理结果
     */
    @GetMapping("feignDemoteCheckFail")
    public String feignDemoteCheckFail(){
        return accountService.feignDemoteCheckFail();
    }

}

到此处我们就完成了我们account-server的编写了,接着我们直接启动我们的account-server。

订单微服务

接着我们创建我们的订单微服务【feign-demote-order】,账户微服务需要调用我们的账户微服务因此需要在引入eureka的基础上海需要引入我们的feign的依赖,创建完成以后修改我们的pom.xml修改完以后代码如下:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.cloud.feign.demote</groupId>
    <artifactId>feign-demote-order</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>feign-demote-order</name>
    <description>订单模块</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR1</spring-cloud.version>
    </properties>

    <dependencies>
        <!--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>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

接着修改我们的主入口类【FeignDemoteOrderApplication.java】,将当前的工程配置为eureka的客户端,同时开启我们的feign,代码如下:

/**
 * @author linzf
 * @since 2019-12-26
 * 类描述: 订单的主入口类
 */
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class FeignDemoteOrderApplication {

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

}

最后修改我们的application.yml配置文件,可能你创建的时候是application.properties,直接修改后缀为yml即可,修改以后代码如下:

eureka:
  instance:
    hostname: localhost
    prefer-ip-address: true
  client:
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:8761/eureka/

# 若将这个参数设置为false,将不会触发feign的降级处理
feign:
  hystrix:
    enabled: true

logging:
  level:
    root: INFO
    com:
      cloud:
        feign:
          demote:
            order: DEBUG

server:
  port: 8380
spring:
  application:
    name: order-server

ribbon:
  eureka:
    enabled: true
  ReadTimeout: 120000
  ConnectTimeout: 120000
  MaxAutoRetries: 0
  MaxAutoRetriesNextServer: 0
  OkToRetryOnAllOperations: false
  NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

# 设置断路器超时时间
hystrix:
  threadpool:
    default:
      coreSize: 1000
      maxQueueSize: 1000
      queueSizeRejectionThreshold: 500
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 490000
          strategy: SEMAPHORE


编写我们的账户的feign【AccountFeignDemote】用于当前订单服务来调用,代码如下:

package com.cloud.feign.demote.order.feign;

import com.cloud.feign.demote.order.feign.impl.AccountFeignDemoteImpl;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * @author linzf
 * @since 2019/12/26
 * 类描述:
 */
@FeignClient(value = "account-server", path = "account" ,fallback = AccountFeignDemoteImpl.class)
public interface AccountFeignDemote {

    /**
     * 功能描述: 正常的feign的调用
     *
     * @return 返回处理结果
     */
    @GetMapping("feignDemoteCheckSuccess")
    String feignDemoteCheckSuccess();

    /**
     * 功能描述: 正常的feign的调用
     *
     * @return 返回处理结果
     */
    @GetMapping("feignDemoteCheckFail")
    String feignDemoteCheckFail();

}

编写我们的账户降级的feign【AccountFeignDemote】的实现,用于当调用失败的时候的降级处理,代码如下:

package com.cloud.feign.demote.order.feign.impl;

import com.cloud.feign.demote.order.feign.AccountFeignDemote;
import org.springframework.stereotype.Component;

/**
 * @author linzf
 * @since 2019/12/26
 * 类描述:
 */
@Component
public class AccountFeignDemoteImpl implements AccountFeignDemote {

    @Override
    public String feignDemoteCheckSuccess() {
        return "我被降级处理了";
    }

    @Override
    public String feignDemoteCheckFail() {
        return "我被降级处理了";
    }
}

编写订单的service【OrderService.java】的实现,代码如下:

package com.cloud.feign.demote.order.service;

import com.cloud.feign.demote.order.feign.AccountFeignDemote;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author linzf
 * @since 2019/12/26
 * 类描述:
 */
@Service
public class OrderService {

    private static Logger logger = LoggerFactory.getLogger(OrderService.class);

    @Autowired
    private AccountFeignDemote accountFeignDemote;

    /**
     * 功能描述: 有降级的feign调用的成功的方法
     * @return
     */
    public String feignDemoteCheckSuccess(){
        logger.debug("这是有降级的调用成功以后的方法!");
        return accountFeignDemote.feignDemoteCheckSuccess();
    }

    /**
     * 功能描述: 有降级的feign调用的失败的方法
     * @return
     */
    public String feignDemoteCheckFail(){
        logger.debug("这是有降级的调用失败以后的方法!");
        return accountFeignDemote.feignDemoteCheckFail();
    }

}

编写订单的controller【OrderController.java】的实现,代码如下:

package com.cloud.feign.demote.order.controller;

import com.cloud.feign.demote.order.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author linzf
 * @since 2019/12/26
 * 类描述: 订单的controller
 */
@RestController
@RequestMapping(value = "order")
public class OrderController {

    @Autowired
    private OrderService orderService;

    /**
     * 功能描述: 有降级的feign调用的成功的方法
     * @return
     */
    @GetMapping("feignDemoteCheckSuccess")
    public String feignDemoteCheckSuccess(){
        return orderService.feignDemoteCheckSuccess();
    }

    /**
     * 功能描述: 有降级的feign调用的失败的方法
     * @return
     */
    @GetMapping("feignDemoteCheckFail")
    public String feignDemoteCheckFail(){
        return orderService.feignDemoteCheckFail();
    }

}

到此处我们就完成了我们的订单微服务开发了,我们直接启动我们的订单微服务。

验证feign的降级

在保证我们的三个服务都正常启动,且我们的订单和账户都注册到注册中心的情况下,我们直接打开浏览器输入以下的地址:
http://127.0.0.1:8380/order/feignDemoteCheckFail,我们在控制台会看到如下的页面,则说明服务被降级了:
在这里插入图片描述

若我们希望不要进行全局的降级处理,那我们就直接修改我们的application.yml的配置文件的以下的代码部分,将改值由true改为false即可。
在这里插入图片描述
若我们只希望我们的某个feign不需要降级处理,那么我们直接删除相应的feign接口的fallback即可,删除如下图箭头所示位置的代码即可:
在这里插入图片描述
到此处我们就完成了我们的feign的优雅的降级的demo的实现了,若需要源代码可以关注我的公众号回复hoxton feign即可

发布了128 篇原创文章 · 获赞 72 · 访问量 113万+

猜你喜欢

转载自blog.csdn.net/linzhefeng89/article/details/103710038