Feign-解决远程调用问题

问题引入

在前面的学习中,我们使用了Ribbon的负载均衡功能,大大简化了远程调用时的代码:

String baseurl = "http://user-service/user/" ;
User user = this.restTemplate.getForobject(baseUrl + id, User.class);

但是可能以后需要编写类似的大量重复代码,格式基本相同,无非参数不一样而已,而且例如这里的user-service服务名称我们可以通过eureka获取,但是user这个路径怎么知道呢?
Feign就能很好的解决这个远程调用的问题。

Feign

  • 较为官方的解释:
    Feign是一个声明性的Web服务客户端。它使编写Web服务客户端变得更容易。feigin是一种模板化,声明式的http客户端,feign可以通过注解绑定到接口上来简化Http请求访问。与当我们访问别的服务端口的时候 大部分使用httpclient等请求进行调用不同,在eureka注册的服务,我们可以使用Feign 声明接口的形式来进行相关服务的调用,并提供了失败回退(其实是Hystrix组件的使用)。Feign只是一个便利的rest框架,简化调用,最后还是通过ribbon在注册服务器中找到服务实例,然后对请求进行分配。
  • 我的理解:
    Feign可以把例如上面这样的远程请求给隐藏起来,让别人看不到,看起来好像是在访问本地服务一样,有一种伪装功能。Feign替我们解决这件事的时候,我们也应该去告诉他 请求路径、请求参数、请求方式、返回结果,仔细想想这四个东西springmvc的注解就可以搞定,我们的controller方法,有@RequestMapping(method属性)、@PathVariable、return返回值。所以Feign就可以利用springmvc的注解识别这些信息,帮我们远程调用,不用我们写。

Feign的使用

引入依赖并启动

<!--feign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
@EnableFeignClients
@SpringCloudApplication
public class ConsumerApplication {
    /*这个也不需要了,注释掉
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }*/

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

编写注解类

这个注解类,其实就是Feign的一个客户端
@FeignClient("user-service"):这个注解时指定服务名,去eureka拉取服务列表,然后底层利用ribben进行负载均衡挑选任意一个服务。访问@GetMapping(“user/findById/{id}”)路径,参数为id,返回一个User对象的json字符串,全部自动完成。

@FeignClient("user-service")
public interface UserClient {
    @GetMapping("user/findById/{id}")
    User findByid(@PathVariable("id")Integer id);
}

修改ConsumerController类

ConsumerController是服务调用端的一个controller类。

@RestController
@RequestMapping("/consumer")
@DefaultProperties(defaultFallback = "findByIdFallback")
public class ConsumerController {
    @Autowired//注入UserClient 
    private UserClient userClient;

    @GetMapping("{id}")
    public User findById(@PathVariable("id")Integer id){
        return userClient.findByid(id);
    }
    //默认fallback方法,不需要再有参数了
    public String findByIdFallback(){
        return "不好意思!服务器正忙!!!!";
    }
}

userClient.findByid(id):这样的调用,是不是像在调用本地的一个方法一样,但是本质是进行了远程调用,很优雅。

Feign与负载均衡与服务降级

思考:在上面的代码中,我们只告诉了服务调用者服务名称是user-service,并没有告诉他ip地址,但是他却能实现访问服务并调用功能,说明他内部是有负载均衡处理的。
在这里插入图片描述
我们看看feign的包依赖,他内部是有ribbon的实现了负载均衡、hystrix实现了服务熔断和降级的,而且此时我们如果引入了这个Feign,那么这两个依赖就不需要在去单独引入依赖了。

feign与ribbon负载均衡

而且ribbon的负载均衡和以前使用方式是一样的,Feign还内置了一个超时时长默认1秒钟。我们可以在application.yml中进行配置。

ribbon:
  ConnectionTimeOut: 1000 # 建立连接的超时时长(1秒未建立就超时)
  ReadTimeOut: 1000 # 读取数据超时时长(1秒未读取就超时)

feign与hystrix熔断

注意Hystrix在feign中默认是关闭的,我们应该在application.yml中进行开启。

# 开启feign的hystrix功能
feign:
  hystrix:
    enabled: true

需要注意的是,Feign底层在实现熔断时,没有走Springcloud提供的方式,之前我们的配置的值是可用的,但是写法变了,我们需要自己去写一个熔断类。
这个类必须实现我们的UserClient接口,并且要注入到容器中。

@Component
public class UserClientFallBack implements UserClient {
    @Override
    public User findByid(Integer id) {
        User user=new User();
        user.setId(id);
        user.setUsername("用户查询异常!!");
        return user;
    }
}

UserClient类的@FeignClient(value = "user-service",fallback =UserClientFallBack.class )指定自定义熔断类。

@FeignClient(value = "user-service",fallback =UserClientFallBack.class )
public interface UserClient {

    @GetMapping("user/findById/{id}")
    User findByid(@PathVariable("id")Integer id);
}

测试

启动服务器,测试一下在这里插入图片描述
未关闭前,一切正常。可以查出数据。
在这里插入图片描述

关闭服务提供者UserApplication服务器,肯定会出现远程连接异常,此时就会得到我们自定义的那个熔断类对应方法返回的信息了。
在这里插入图片描述
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章