Spring Cloud OpenFeign 使用

Feign是一个声明性web服务客户端,它使得编写web服务客户端变得更加容易,Spring Cloud Feign是基于Netflix Feign实现,整合了Spring Cloud Ribbon与Spring Cloud Hystrix,除了提供两者强大功能外,它还提供了声明式的Web服务客户端定义方式

1.Feign和OpenFeign的区别是什么

Feign是Spring Cloud组件中一个轻量级RESTful的HTTP服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用接口,就可以调用服务注册中心的服务

引入依赖

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

OpenFeign是Spring Cloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类

引入依赖

    <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency> 

2.使用Openfeign实现负载均衡

 参考代码: GitHub - PNZBEIJINGL/spring-cloud-lab  

服务 IP 端口
eureka-peer 127.0.0.1 1000 Eureka服务注册中心
openfeign-consumer 127.0.0.1 8004 消费服务(测试Feign调用使用)
ms-customer 127.0.0.1 8001 客户服务
ms-customer_interface 客户接口工程

2.1 ms-customer应用

提供2个RestController访问

    /**
     * http://127.0.0.1:8001/time/
     */
    @RequestMapping(value = "/time", method = RequestMethod.GET)
    public String time() {

        return  new Date().toString();
    }

    /**
     * http://127.0.0.1:8001/customer/1
     */
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public CustomerDTO getCustomer(@PathVariable("id") Long customerId) throws InterruptedException {
        //测试阻塞几秒
        int sleepTime=new Random().nextInt(4000);
        Thread.sleep(sleepTime);

        ServiceInstance instance = discoveryClient.getLocalServiceInstance();
        String message = " host:" + instance.getHost() + ",service_id:" + instance.getServiceId();
        logger.info(message + " "+sleepTime);

        CustomerDTO customer = mockCustomer();
        customer.setId(customerId);
        return customer;
    }

 2.2openfeign-consumer应用

扫描二维码关注公众号,回复: 13594063 查看本文章

feign-consumer应用的pom.xml配置增加依赖,并设置application.properties配置使用端口8004

<dependencies>

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

        <!-- 注册服务提供 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>

        <!-- 引入openfeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

        <!-- 依赖接口ms-customer-interface -->
        <dependency>
            <groupId>spring.cloud.test</groupId>
            <artifactId>ms-customer-interface</artifactId>
            <version>1.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
            <scope>test</scope>
        </dependency>


    </dependencies>
server.port=8004

#服务的名称
spring.application.name=OPENFEIGN-CONSUMER

############ Eureka ################
#服务注册中心IP
eureka.instance.hostname=127.0.0.1
#指定服务注册中心
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:1000/eureka/
############ Eureka ################

启动主类增加@EnableFeignClients注解将Feign可用

@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class OpenfeignApplication {

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

}

创建CustomerService 接口,实现MS-CUSTOMER 服务调用

@FeignClient(value = "MS-CUSTOMER")
public interface CustomerService {

    //不带参数
    @RequestMapping("/time")
    public String time() ;

    //带参数
    @RequestMapping(value = "/customer/{id}" ,method = RequestMethod.GET)
    public String getCustomerById(@RequestParam("id") Long id);
}

 创建OpenFeign测试接口

当访问http://127.0.0.1:8004/openfeign/gettime时候,调用CustomerService #time,实现调用访问

MS-CUSTOMER服务提供的服务 http://127.0.0.1:8001/time/

@RestController
public class TestCustomerController {
    @Autowired
    private CustomerService customerService;

    //http://127.0.0.1:8004/openfeign/gettime
    @RequestMapping(value = "/openfeign/gettime",method = RequestMethod.GET)
    public String testMSCustomer(){
        return customerService.time();
    }

    //http://127.0.0.1:8004/openfeign/getcustomer
    @RequestMapping(value = "/openfeign/getcustomer", method = RequestMethod.GET)
    public String  testGetCustomerName(){
        return customerService.getCustomerById(999L);
    }
}

2.3 测试feign-consumer中的Feign调用

  1. 启动eureka-peer 服务中心,
  2. 启动ms-customer服务后ms-customer服务注册到eureka中,
  3. 启动openfeign-consumer 服务
  4. 测试

访问:http://127.0.0.1:8004/openfeign/gettime

访问http://127.0.0.1:8004/openfeign/getcustomer


3. FeignClient注解支持占位符

修改FeignClient注解配置中的服务名,


@FeignClient(name = "${customer.server.name}")
public interface CustomerService {

    //不带参数
    @RequestMapping("/time")
    public String time() ;

    //带参数
    @RequestMapping(value = "/customer/{id}" ,method = RequestMethod.GET)
    public String getCustomerById(@RequestParam("id") Long id);
}

application.config中增加配置实现通过配置customer.server.name替代了服务名,


#客户服务名称配置,也可以配置到配置中心
customer.server.name=MS-CUSTOMER

 访问 http://127.0.0.1:8004/openfeign/getcustomer


4. Feign Hystrix 支持

如果Hystrix在classpath同时 feign.hystrix.enabled=true,Feign将会用断路器包装所有的方法

#开启hystrix支持
feign.hystrix.enabled=true;

#属性用来配置HystrixCommand.run()的执行是否启动超时时间
#如果设置为false,hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds配置将会失效
#默认为true
hystrix.command.default.execution.timeout.enabled=true

#属性用来配置HystrixComman执行的超时时间,单位毫秒,当HystrixCommand执行时间
#超过配置的值后, Hystrix会执行命令标记为TIMOUT并进入服务降级处理逻辑
#默认1000毫秒
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=3000

 通过@FeignClient注解中的 fallback实现Hystrix Fallback支持


@FeignClient(name = "${customer.server.name}" ,fallback = CustomerService.CustomerServiceFallback.class)
public interface CustomerService {

    //不带参数
    @RequestMapping("/time")
    public String time() ;

    //带参数
    @RequestMapping(value = "/customer/{id}" ,method = RequestMethod.GET)
    public String getCustomerById(@RequestParam("id") Long id);

    @Component
    class CustomerServiceFallback implements CustomerService{

        @Override
        public String time() {
            return "fallback";
        }

        @Override
        public String getCustomerById(Long id) {
            return "fallback";
        }
    }

}

如果需要知道异常内容可以使用fallbackFactory  实现

@FeignClient(name = "${customer.server.name}" ,fallbackFactory  = CustomerService.CustomerServiceFallbackFactory.class)
public interface CustomerService {

    //不带参数
    @RequestMapping("/time")
    public String time() ;

    //带参数
    @RequestMapping(value = "/customer/{id}" ,method = RequestMethod.GET)
    public String getCustomerById(@RequestParam("id") Long id);

    static class CustomerServiceFallbackFactory implements FallbackFactory<CustomerService> {

        @Override
        public CustomerService create(final Throwable cause) {
            return new CustomerService() {
                @Override
                public String time() {
                    return "fallback,cause:" + cause.getMessage();
                }

                @Override
                public String getCustomerById(Long id) {
                    return "fallback,cause:" + cause.getMessage();
                }
            };
        }
    }
}

注: 如果在测试过程中发现Incompatible fallback instance异常, 是因为@FeignClient注解中fallbackFactory  或者 fallback 设置的类不匹配引起

5. 超时处理

我们可以在客户端设置超时时间,OpenFeign超时时间有两种设置

  • connectTimeout : 服务器处理时间过长时触发
  • readTimeout:从建立连接开始至返回响应期间的时间过长时触发
feign.client.config.default.connectTimeout=5000
feign.client.config.default.readTimeout=5000

      当服务器没有运行或者不可用,数据包会被连接拒绝,通信将会返回错误消息或者fallback信息,这可能是由于connectTimeout 设置的非常低造成的

      当Hystrix 配置成可用的时候,其默认的超时时间是1000毫秒,我们设置的两种超时时间都在5000,因此它可能发生在我们配置的超时时间之前,因此增加超时时间可以防止这类情况发生。

      当Hyestrix配置成可用且配置的时间比feign的超时时间长的候,HystrixTimeoutException异常将会包装feign的异常 ,HystrixTimeoutException异常的作用就是包装任何提前发生的运行时异常(Runtime exception) 然后抛出自身的实例

  上一篇:Spring Cloud Feign启动Load balancer does not have available server for client

猜你喜欢

转载自blog.csdn.net/Beijing_L/article/details/121406870