Spring Cloud Netflix Feign

得意时要看淡,失意时要看开。不论得意失意,切莫大意;不论成功失败,切莫止步。志得意满时,需要的是淡然,给自己留一条退路;失意落魄时,需要的是泰然,给自己觅一条出路Spring Cloud Netflix Feign,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

Fegin简介

Fegin是一个声明式的Http客户端,它使得写Http客户端变得更简单,使用Fegin只需要创建一个接口并注解,它具有可插拔的注解特性,Nacos很好的兼容了Fegin,默认实现了负载均衡的效果,底层使用了HttpClient作为服务框架。

Spring Cloud 集群中,各个角色的通信基于 REST 服务,因此在调用服务时,就不可避免地需要使用 REST 服务的请求客户端。之前一直使用的是 Spring 自带的 RestTemplate,而RestTemplate 使用 了HttpClient 发送请求。接下来将介绍另一个 REST 客户端: Feign。Feign 框架己经被集成到 Spring Cloud Netflix 项目中,使用该框架可以在 Spring Cloud 的集群中更加简单地调用REST 服务。

在这里插入图片描述

在这里插入图片描述

Web Service

使用 CXF 调用 REST 服务

CXF 是目前一个较为流行的 Web Service 框架,是 Apache 个开源项目。使用 CXF可以发布和调用使用各种协议的服务,包括 SOAP 协议、 XML/HTTP 等。当前 CXF 已经对REST 风格的 Web Service 提供支持,可以发布或调用REST 风格的 Web Service 。由于CXF 可以与 Spring 进行整合使用并且配置简单,因此得到许多开发者的青睐,所使用的 CXF 需要在 Maven 中加入以下依赖:

在这里插入图片描述
编写代码请求/person/{persionid}服务:

在这里插入图片描述
客户端中使用了WebClient类发送了请求,获取响应后读取数据流,获取服务返回json字符串。

使用Restlet调用REST服务

Restlet是一个轻量级的REST框架,使用它可以发布和调用REST风格的Web Service。

在这里插入图片描述
在这里插入图片描述
使用Restlet的api比较简单,但是Maven中央仓库没有Restlet包,需要在pom.xml中添加以下配置:

在这里插入图片描述

RestTemplate调用REST服务

RestTemplate位于org.springframework.web.client.RestTemplate包spring mvc框架的类,也具有调用http协议的功能。

Spring Cloud Netflix Feign框架

Feign框架也是一个类似的框架,简化了Web Service客户端的开发,在使用Feign时可以使用注解来修饰接口,被注解修饰的接口具有访问Web Service的能力。

Spring Cloud 将Feign集成到Netflix项目中,与Eureka,Ribbon集成时,Feign就具有了负载均衡的功能。与Spring 的整合极大的提高了简洁性。

在这里插入图片描述

Feign组件的使用

对于Feign的调用和之前使用RestTemplate完全不一致,首先对于微服务的调用一定都是基于服务治理的,Feign也遵守,使用RestTemplate对象时是基于@RestController控制器进行,而Feign基于自生注解@FeignClient实现,不再仅仅是调用API接口实现服务调用,而是整个客户端都由Feign提供。

在服务额调用者中实现:

  1. 导入依赖
<!--feign实现微服务的调用-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>3.1.3</version>
        </dependency>

注意是openfeign而不是netflix-feign

  1. 配置调用接口
/**
 * 声明微服务名称
 */
@FeignClient(name = "bill-service")
public interface BillClient {
    //配置微服务调用接口
    @GetMapping(value = "/bill/{id}")
    BillMessage getBuId(@PathVariable("id") Integer id);
}


  1. 在启动类上注解激活feign
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class TestModuleApplication {

    @LoadBalanced
    @Bean
    public RestTemplate getRestTemplate(){ return new RestTemplate(); }

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

}

//核心是@EnableFeignClients

  1. 通过自动的接口调用远程服务
/**
 * 基于feign实现微服务
 */
@RestController
@RequestMapping(value = "/test1")
public class Test2Controller {

    @Autowired
    private BillClient billClient;

    @GetMapping(value = "/feign/{id}")
    public BillMessage method1(@PathVariable("id") Integer id){
        BillMessage buId = billClient.getBuId(id);
        return buId;
    }
}

服务任然可以调用:

在这里插入图片描述

还遇到了一个错误就是Could not find class [org.springframework.cloud.client.loadbalancer.LoadBalancerProperties]

出现该错误的原因是spring-cloud-starter-openfeign版本过低,升级版本即可。

工作原理解析

在这里插入图片描述
在这里插入图片描述

对比前几个调用方式:

@RestController
@RequestMapping(value = "/test")
public class TestController {


    //获取服务中心实例
    @Autowired
    private DiscoveryClient discoveryClient;

    //java代码访问api接口的实例对象


    @Autowired
    private RestTemplate restTemplate;

    //bill_service的调用
    @GetMapping(value = "/bill/{id}")
    public BillMessage testMethod1(@PathVariable Integer id){
        List<ServiceInstance> bill_service = discoveryClient.getInstances("bill_service");
        //该服务只有一个
        ServiceInstance instance = bill_service.get(0);

        BillMessage billMessage = restTemplate.getForObject(instance.getUri() + "/bill/" + id, BillMessage.class);
        System.out.println(instance.getUri());
        return billMessage;
    }


    //使用Ribbon获取服务
    @GetMapping(value = "/bill1/{id}")
    public BillMessage testMethod2(@PathVariable Integer id){
        BillMessage billMessage = restTemplate.getForObject("http://bill-service/bill/"+id,BillMessage.class);
        return billMessage;
    }


}

通过服务实例ServiceInstance获取服务信息,在通过RestTemplate访问接口,步骤比较繁琐;第二种通过Ribbon获取,封装了服务实例的获取,直接通过服务名调比较方便。对于feigin呢?

/**
 * 基于feign实现微服务
 */
@RestController
@RequestMapping(value = "/test1")
public class Test2Controller {

    @Autowired
    private BillClient billClient;

    @GetMapping(value = "/feign/{id}")
    public BillMessage method1(@PathVariable("id") Integer id){
        BillMessage buId = billClient.getBuId(id);
        return buId;
    }
}
/**
 * 声明微服务名称
 */
@FeignClient(name = "bill-service")
public interface BillClient {
    //配置微服务调用接口
    @GetMapping(value = "/bill/{id}")
    BillMessage getBuId(@PathVariable("id") Integer id);
}

Feign设置了代理服务,调用先通过Proxy也兼顾负载均衡功能,还可以用服务名调用,在Rest接口调用时直接通过代理服务获取
甚至省去了url的拼接,极其方便。Spring Cloud对Feign进行了增强,使Feign支持了Spring MVC注解,并整合了Ribbon和Eureka,从而让Feign的使用更加方便。

feign的设计原理
在这里插入图片描述

通过Feign的代理可以帮助我们解决很多问题。由于我们的服务调用都是基于Http协议进行的,所以代码中不得不使用Http相应的客户端来进行服务间沟通。RestTemplate是Spring Web提供的Http客户端,但是使用 RestTemplate 时代码可读性差,并且参数复杂 url 难维护。Feign是一个声明式的http客户端,其作用就是帮助我们优雅地实现http请求的发送,解决上面提到的问题。

总结

feign框架的使用四个步骤:

  1. 导入spring-cloud整合feign的依赖;
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  1. 添加feign的配置启动类
@SpringBootApplication
//@EnableDiscoveryClient
@EnableFeignClients
public class TestModuleApplication {
	/*
    @LoadBalanced
    @Bean
    public RestTemplate getRestTemplate(){ return new RestTemplate(); }
	*/
    public static void main(String[] args) {
        SpringApplication.run(TestModuleApplication.class, args);
    }

}
  1. 创建feign接口代理类,解析服务实例
@FeignClient(name = "bill-service")
public interface BillClient {
    //配置微服务调用接口
    @GetMapping(value = "/bill/{id}")
    BillMessage getBuId(@PathVariable("id") Integer id);
}

//FeignClinet代理根据配置名称,通过GetMapping接口获取服务实例信息并解析,其方法返回值为接口返回Bean对象,无需解析赋值过程。
  1. 获取feign代理服务类,获取返回实例
/**
 * 基于feign实现微服务
 */
@RestController
@RequestMapping(value = "/test1")
public class Test2Controller {
	
	//获取feign代理实例
    @Autowired
    private BillClient billClient;


    @GetMapping(value = "/feign/{id}")
    public BillMessage method1(@PathVariable("id") Integer id){
    	//feign代理实例获取的服务实例对象的接口返回值信息赋值,在调用接口赋值。
        BillMessage buId = billClient.getBuId(id);
        return buId;
    }
}

feign的配置

可通过一些自定义配置来覆盖 feign 的默认配置,可以修改的配置如下:

在这里插入图片描述
配置Feign日志有两种方式:1.配置文件方式、2.java代码方式

  • 配置文件
#全局生效
feign:
  client:
    config:
      default:   # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
        loggerLevel: FULL  #  日志级别
#局部生效
feign:
  client:
    config:
      userservice:   # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
        loggerLevel: FULL  #  日志级别
  • 通过Java代码自定义配置
public class FeignClientConfiguration {
    @Bean
    public Logger.Level feignLogLevel(){
        return Logger.Level.BASIC;
    }
}

然后如果是全局配置,则把它放到 @EnableFeignClients 这个注解中:

@SpringBootApplication
@EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class)
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}

如果是局部配置,则把它放到 @FeignClient 这个注解中:

@FeignClient(value = "userservice", configuration = FeignClientConfiguration.class)
public interface UserClient {
    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}

更多配置信息参考feign自定义配置感谢作者@wenxuehai

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/156248.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!