Spring Cloud之Feign消费和Hystrix熔断

Spring Cloud的Feign消费和Hystrix熔断

现如今,由于互联网的流行,很多特产都可以在网上订购,你可以在堆满积雪的冬北订购海南的椰子,海南的椰子就会采用很快的物流方式调送到堆满积地的东北,就相当于在本地实现了买椰子的举动,这种远程调用的方法称为Feign。如下图所示。

Spring Cloud之Feign消费和Hystrix熔断_第1张图片

 

一、Feign的解释

Feign 主要是帮助我们方便进行rest api服务间的调用,其大体实现思路就我们通过标记注解在一个接口类上(注解上将包含要调用的接口信息),之后在调用时根据注解信息组装好请求信息,通过服务器获取生成真实的服务地址,最后将请求发送出去;之后将接收到的结果反序列化为相关的Java对象供我们直接使用。

Feign在实际应用中通过在启动类上标记 @EnableFeignClients 注解来开启feign的功能,服务启动后会扫描 @FeignClient 注解标记的接口,然后根据扫描的注解信息为每个接口类生成feign客户端请求,同时解析接口方法中的Spring MVC的相关注解,通过专门的注解解析器识别这些注解信息,以便后面可以正确的组装请求参数,使用Eureka 获取到请求服务的真实地址等信息,最后使用 http 相关组件进行执行调用。其大致流程图如下:

Spring Cloud之Feign消费和Hystrix熔断_第2张图片

 

在Feign的通信过程中,可能会出现服务器荡机的状况,Hystrix起到了一定的熔断保护措施。

二、Hystrix的解释

Hystrix是一个用于处理分布式系统的延迟和容错开源库,在分布式系统中,许多依赖不可避免的会调用失败,比如超时,异常等,Hystrix能保证在一个依赖出现问题时,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。

hystrix提供了五种理论技术,如下:

1、降级:当调用出现异常或超时等无法返回正常数据时,返回一个合理的结果或实现fallback方法,针对客户端而言。

2、熔断:当失败率达到阈值自动触发降级,这里的熔断就是具有特定条件的降级,当出现熔断时在设定的时间内不在请求。熔断有自动恢复机制,举个例子说,当熔断器启动后,每隔10秒,尝试将新的请求发送给service,如果服务可正常执行并返回结果,则关闭熔断器,恢复服务。如果仍调用失败,则继续返回fallback,熔断器持续开启。

3、请求缓存:服务A调用服务B,如果在A中添加请求缓存,第一次请求后走缓存,不在访问微服务B,即使出现大量请求,不会对B产生高负荷。请求缓存可以使用spring cache实现。

4、请求合并:当服务A调用服务B时,设定在5毫秒内所有请求合并到一起,对于服务B的负荷就会减少。使用@HystrixCollapser。方法返回值必须为Future

5、隔离:隔离分为线程池隔离合信号量隔离。通过判断线程池或信号量是否满,超过容量的请求直接降级,从而达到限流。

Hystrix可以理解成电路中的保险丝,线路不通还有那么一层保护,如下图所示。

Spring Cloud之Feign消费和Hystrix熔断_第3张图片

 

三、产品的eureka服务器的启动

1、点击File--->New---->Project.....,如下图。

Spring Cloud之Feign消费和Hystrix熔断_第4张图片

 

2、在弹出的地话框中,左边点击Spring Initializr,表示Spring的初始程序,右边在默认的地方可能会初始化失败,需要选择自定义的地址:http://start.aliyun.com。如右图所示。

Spring Cloud之Feign消费和Hystrix熔断_第5张图片

 

3、在接下来的弹出框中输入spring cloud项目名称的Group和artifactId。如下图所示。

Spring Cloud之Feign消费和Hystrix熔断_第6张图片

 

4、点击Next进入下一步,左边先点击Web,右边点击Spring web可以建立Web应用程序。如下图。

Spring Cloud之Feign消费和Hystrix熔断_第7张图片

 

5、继续在这个对话框中,左边点击Spring Cloud Discovery,右边点击Eureka Server,如下图所示。

Spring Cloud之Feign消费和Hystrix熔断_第8张图片

 

6、然后点击Next进入到“下一步”,会出现对话框。如下图所示。

Spring Cloud之Feign消费和Hystrix熔断_第9张图片

 

7、在出现的对话框中,点击Finish后完成项目的构建向导。

项目框架建立后,修改主程序中的主类,如下图所示。

Spring Cloud之Feign消费和Hystrix熔断_第10张图片

 

8、在打开的主程序中,加入注解@EnableEurekaServer。如下图所示。

Spring Cloud之Feign消费和Hystrix熔断_第11张图片

 

最终,eurekaserver的程序代码如下。

package com.myfirsteurekabalance.myfirsteurekabalance;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class MyfirsteurekabalanceApplication {

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

}

9、下面需要编辑resources下面的application.yml文件,在原来的resouces目录下只有application.properties,需要把application.properties改成application.yml。然后编辑该文件。

Spring Cloud之Feign消费和Hystrix熔断_第12张图片

 

10、application.yml的文件内容如下。

# 应用名称
spring:
  application:
    name: myfirsteurekabalance
# 应用服务 WEB 访问端口
server:
  port: 8819
eureka:
  client:
    register-with-eureka: true
    fetch-registry: false
    service-url:
      defaultZone: http://localhost:8819/eureka
  instance:
    hostname: myprovider1

其文件内容的解释如下 。

Spring Cloud之Feign消费和Hystrix熔断_第13张图片

 

四、产品的Feign客户端的搭建

1、同样点击File--->New----->Project....,如下图所示。

Spring Cloud之Feign消费和Hystrix熔断_第14张图片

 

2、在打开的对话框中,左边继续点击Spring Initializr,表示Spring的初始程序,右边在默认的地方可能会初始化失败,需要选择自定义的地址:http://start.aliyun.com。如下图所示。

Spring Cloud之Feign消费和Hystrix熔断_第15张图片

 

3、点击Next,然后在出现的对话框中输入项目名称。如下图所示。

Spring Cloud之Feign消费和Hystrix熔断_第16张图片

 

4、在接下来出现的对话框中,左边选择Web,右边选择Spring Web。如下图所示。

Spring Cloud之Feign消费和Hystrix熔断_第17张图片

 

5、继续在这个对话框中,左边选择Spring Cloud Discovery,右边选择Eureka Discovery Client。如下图所示。

Spring Cloud之Feign消费和Hystrix熔断_第18张图片

 

6、然后点击左侧的Spring Cloud Routing,然后点右侧的OpenFeign。再点击Next。

Spring Cloud之Feign消费和Hystrix熔断_第19张图片

 

7、然后点击下一步即Next,在出现的对话框中直接点击Finish完成项目建立的向导。如下图所示。

Spring Cloud之Feign消费和Hystrix熔断_第20张图片

 

项目完成后,接下来设置pom.xml中需要用到的依赖包,具体依赖内容如下。


    
        org.springframework.boot
        spring-boot-starter-web
    
    
        org.springframework.cloud
        spring-cloud-starter-netflix-eureka-client
    
    
        org.springframework.cloud
        spring-cloud-starter-openfeign
    
    
        org.springframework.cloud
        spring-cloud-starter-netflix-hystrix
        2.2.10.RELEASE
    
    
        org.projectlombok
        lombok
        1.18.0
    
    
        org.springframework.cloud
        spring-cloud-starter-zipkin
        2.2.8.RELEASE
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    

这里面后加入的依赖是spring-cloud-starter-zipkin、lombok、spring-cloud-starter-netflix-hystrix。具体依赖的内容如下。


    org.springframework.cloud
    spring-cloud-starter-netflix-hystrix
    2.2.10.RELEASE


    org.projectlombok
    lombok
    1.18.0


    org.springframework.cloud
    spring-cloud-starter-zipkin
    2.2.8.RELEASE

8、这里是需要Feign的fallback,Fallback可以帮助我们在使用Feign去调用另外一个服务时,如果出现了问题,走服务降级,返回一个错误数据,避免功能因为一个服务出现问题,全部失效。需要首先定义feign包,然后产生feign的java包。这里feign的包中包括两个Feign消费端,一个是Product的Feign消费端,一个是Order的Feign消费端。结构如下。

Spring Cloud之Feign消费和Hystrix熔断_第21张图片

 

对于ProductFeign需要使用FegnClient指定消费客户端,同时指定消费在eureka注册中心的服务器名称,并且指明如果服务出现问题的服务降级错误处理fallback。

注意,这里的feign是一个接口,代码如下。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.stereotype.Component;
@FeignClient(name="myprovider5",fallback= ProductFallBackMethod.class)
public interface ProductFeign {
    @GetMapping("/product/lists")
    public String lists();
}

对于OrderFeign的代码也是做这样的处理,代码如下。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.stereotype.Component;
@FeignClient(name="myprovider4",fallback= OrderFallBackMethod.class)
public interface OrderFeign {
    @GetMapping("/order/lists")
    public String lists();
}

9、每个feign消费端都指定了一个fallback类方法,所以需要分别定义ProductFallback和OrderFallback的类方法,可以把这两个类放在fallback包下面.结构如下图。

Spring Cloud之Feign消费和Hystrix熔断_第22张图片

 

在ProductFallbackMethod方法中实现定义的Feign接口,并且重写ProductFeign接口中的lists方法.特别注意的是这个类必须使用@Component注解来说明,不然spring cloud找不到这个fallback方法。代码如下。

package com.example.mymicroservice1.fallback;

import com.example.mymicroservice1.feigns.ProductFeign;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class ProductFallBackMethod implements ProductFeign {
    @Override
    public String lists() {
        log.info("ProductFacllbackMethod调用异常");
        return "ProductFacllbackMethod调用异常";

    }
}

代码中的log只是输出日志文件, return是返回到网页中的显示数据,这里的log使用lombok的Slf4j注解来实现,实现后就会有log的声明。

同理实现OrderFallBackMethod方法,代码如下。

import com.example.mymicroservice1.feigns.OrderFeign;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class OrderFallBackMethod implements OrderFeign {
    @Override
    public String lists() {
        log.info("OrderFallBackMethod调用异常");
        return "OrderFallBackMethod调用异常";
    }
}

实现了这个fallback类后,对这两个Feign的调用可以通过service来实现,首先可以建立services包,然后建立一个微服务接口,注意,这里是接口, queryProductList方法中未来会实现ProductFeign, queryOrderList方法中未来会实现OrderFeign。

将两个服务放在一个微服务service的接口Micro1Service代码如下。

package com.example.mymicroservice1.services;
public interface Micro1Service {
    String queryProductList();
    String queryOrderList();
}

接下来定义第一个微服务Micro1Service接口的实现类。services包的结构图如下。

Spring Cloud之Feign消费和Hystrix熔断_第23张图片

 

这里建立一个impl包,在impl包下面建立Micro1Service的接口的实现类Micro1ServiceImpl.代码如下。

package com.example.mymicroservice1.services.impl;

import com.example.mymicroservice1.feigns.OrderFeign;
import com.example.mymicroservice1.feigns.ProductFeign;
import com.example.mymicroservice1.services.Micro1Service;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@Service
@Slf4j
public class Micro1ServiceImpl  implements Micro1Service {
    @Autowired
    private ProductFeign productFeign;
    @Autowired
    private OrderFeign orderFeign;
    @Override
    public String queryProductList() {
        String lists=productFeign.lists();
        log.info("ProductFeign调用返回结果:{}",lists);
        return lists;
    }

    @Override
    public String queryOrderList() {
        String lists=orderFeign.lists();
        log.info("OrderFeign调用结果返回:{}",lists);
        return lists;
    }
}

注意,这里的Micro1ServiceImpl实现类需要实现接口Micro1Service,同时需要使用注解Service,这样Spring Cloud可以得到这样的Service.在Service代码中将ProductFeign和OrderFeign 注入到Service当中,再实现Micro1Service的两个方法。在两个方法中分别调用ProductFeign和OrderFeign的lists接口。最后返回lists()接口返回的数据。

Service代码设置成功后,设置Controller控制器的代码,在控制器实现ProductList商品列表的显示及OrderList订单列表的显示.同时需要RestController对于页面返回数据的显示,在控制器中第一个微服务Micro1Service也需要注入到Controller控制器中。

代码如下。

package com.example.mymicroservice1.controller;
import com.example.mymicroservice1.services.Micro1Service;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@Slf4j
@RestController
@RequestMapping("/micro1")
public class Micro1Controller {
    @Autowired
    private Micro1Service micro1service;
    @RequestMapping("/productList")
    public String productList(){
        return micro1service.queryProductList();
    }
    @RequestMapping("/orderList")
    public String orderList(){
        return micro1service.queryOrderList();
    }
}

因为这个项目中使用Feign消费端,所以需要在主启动类中加入@EnableFeignClients的注解.代码如下。

package com.example.mymicroservice1;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
public class Mymicroservice1Application {

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

}

最后的yml文件中需要设置客户端feign的启动,新版本的启动hystrix使用circuitbreaker,代码如下。

spring:
  application:
    name: myprovider2
  zipkin:
    base-url: http://localhost:9411/
  sleuth:
    sampler:
      probability: 1.0
server:
  port: 8830
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8819/eureka
  instance:
    hostname: myprovider2
feign:
  circuitbreaker:
    enabled: true

五、产品的Product消费端的产生.

1、同样点击File--->New----->Project....,如下图所示。

Spring Cloud之Feign消费和Hystrix熔断_第24张图片

 

2、在打开的对话框中,左边继续点击Spring Initializr,表示Spring的初始程序,右边在默认的地方可能会初始化失败,需要选择自定义的地址:http://start.aliyun.com。如下图所示。

Spring Cloud之Feign消费和Hystrix熔断_第25张图片

 

3、点击Next,然后在出现的对话框中输入项目名称。如下图所示。

Spring Cloud之Feign消费和Hystrix熔断_第26张图片

 

4、在接下来出现的对话框中,左边选择Web,右边选择Spring Web。如下图所示。

Spring Cloud之Feign消费和Hystrix熔断_第27张图片

 

5、继续在这个对话框中,左边选择Spring Cloud Discovery,右边选择Eureka Discovery Client。如下图所示。

Spring Cloud之Feign消费和Hystrix熔断_第28张图片

 

6、然后点击下一步即Next,在出现的对话框中直接点击Finish完成项目建立的向导。如下图所示。

Spring Cloud之Feign消费和Hystrix熔断_第29张图片

 

7、在Product的微服务消费端中需要定义一个Pojo与数据库中的product表相对应。建立pojo对应的包entity,然后在entity包中产生Pojo的类Product。结构如下图所示。

 

8、在Product商品类中定义商品需要的信息。

package com.example.mymicroservice2.entity;
import lombok.Data;
import java.util.Date;
@Data
public class Product {
    private Integer id;
    private String productName;
    private Double productPrice;
    private String crop;
    private Date createTime;
    private Date modifyTime;
    private String remark;
}

这里通过lombok的Data注解来实现类中的Getter和Setter方法。

根据mvc的原理,下面需要根据Product定义dao模型。首先建立dao包,然后来dao包下建立ProductDao接口文件,注意这里是一个接口,结构如下图。

 

在接口文件中,定义接口方法lists,其目的显示product表中的所有数据。同时将接口中的注解Mapper来实现与mybatis和配置文件进行对应。代码如下。

package com.example.mymicroservice2.dao;
import com.example.mymicroservice2.entity.Product;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ProductDao {
    public List lists();
}

这个ProductDao接口需要对应于mybatis的一个ProductDao.xml的mapper文件,mapper文件是存放在resource目录下,结构截图如下。

Spring Cloud之Feign消费和Hystrix熔断_第30张图片

 

mapper文件内容中定义resultMap对应于Product类的类中字段,并通过select方法来完成product表的查询语句SQL操作,ProdudctDao.xml具体代码内容如下。




    
        
        
        
        
        
        
        
    
    

注意mapper文件中resultMap中的column属性指向数据库中字段名,jdbcType指示数据库中的字段类型,property指示java bean中的类属性。