SpringCloud OpenFeign声明式服务调用

目录

一、前言

Feign 是 Netflix 公司发布的一种实现负载均衡和服务调用的开源组件。Spring Cloud 将其与 Netflix 中的其他开源服务组件(例如 Eureka、Ribbon 以及 Hystrix 等)一起整合进 Spring Cloud Netflix 模块中,整合后全称为 Spring Cloud Netflix Feign

Feign 对 Ribbon 进行了集成,利用 Ribbon 维护了一份可用服务清单,并通过 Ribbon 实现了客户端的负载均衡。

Feign 是一种声明式服务调用组件,它在 RestTemplate 的基础上做了进一步的封装。通过 Feign,我们只需要声明一个接口并通过注解进行简单的配置(类似于 Dao 接口上面的 Mapper 注解一样)即可实现对 HTTP 接口的绑定。

Feign 支持多种注解,例如 Feign 自带的注解以及 JAX-RS 注解等,但遗憾的是 Feign 本身并不支持 Spring MVC 注解,这无疑会给广大 Spring 用户带来不便。

2019 年 Netflix 公司宣布 Feign 组件正式进入停更维护状态,于是 Spring 官方便推出了一个名为 OpenFeign 的组件作为 Feign 的替代方案

二、openFeign简介

Open Feign是Spring Cloud的二级子项目。

OpenFeign是一种声明式、模板化的HTTP客户端(仅在Application Client中使用)(称OpenFeign作用:声明式服务调用)。
声明式调用是指,就像调用本地方法一样调用远程方法,无需感知操作远程http请求

Spring Cloud的声明式调用, 可以做到使用 HTTP请求远程服务时能就像调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个HTTP请求。

Feign的应用,让Spring Cloud微服务调用像Dubbo一样,Application Client直接通过接口方法调用Application Service,而不需要通过常规的RestTemplate构造请求再解析返回数据。它解决了让开发者调用远程接口就跟调用本地方法一样,无需关注与远程的交互细节,更无需关注分布式环境开发。

使用OpenFeign时就好像在写控制器方法,OpenFeign都是写在接口中,在声明的方法上添加SpringMVC注解或声明的参数上添加SpringMVC注解就可以完成调用远程的控制器方法。

在这里插入图片描述

Feign 和 OpenFegin的区别:
 
相同点:
(1) Feign 和 OpenFeign 都是 Spring Cloud 下的远程调用和负载均衡组件
(2) Feign 和 OpenFeign 作用一样都可以实现服务的远程调用和负载均衡
(3) Feign 和 OpenFeign 都对 Ribbon 进行了集成,都利用 Ribbon 维护了可用服务清单,并通过 Ribbon 实现了客户端的负载均衡;
(4) Feign 和 OpenFeign 都是在服务消费者(客户端)定义服务绑定接口并通过注解的方式进行配置,以实现远程服务的调用;
 
不同点:
(1) Feign 和 OpenFeign 的依赖项不同Feign 的依赖为 spring-cloud-starter-feign,而 OpenFeign 的依赖为 spring-cloud-starter-openfeign;
(2) Feign 和 OpenFeign 支持的注解不同,Feign 支持 Feign 注解和 JAX-RS 注解,但不支持 Spring MVC 注解;
(3) OpenFeign 除了支持 Feign 注解和 JAX-RS 注解外,还支持 Spring MVC 注解

三、使用OpenFeign时的程序执行流程(原理)

OpenFeign代替之前的RestTemplate代码。也是写在Application Client中把OpenFeign接口单独放在feign包中,表示服务调用层。当需要调用其他服务时,直接注入OpenFeign接口对象就可以像调用本地方法一样调用远程服务

整体流程说明:

  1. ApplicationService 向Eureka Server 注册服务。

  2. Application Client从Eureka Server中发现服务信息,获取服务列表。

  3. 在Application Client中调用OpenFeign接口中方法

  4. Application Client中OpenFeign通过应用程序名调用Application Service

在这里插入图片描述

四、Feign的应用

1.搭建SpringCloud服务注册中心

创建Springboot项目,添加如下依赖:

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

配置application.properties:

## 端口号
server.port=8083
## eureka主机名
eureka.instance.hostname=localhost
## 指定当前主机是否需要向注册中心注册(不用,因为当前主机是Server,不是client)
eureka.client.register-with-eureka=false
## 指定当前主机是否需要获取注册信息(不用,因为当前主机是Server,不是client)
eureka.client.fetch-registry=false
## 注册中心地址
eureka.client.service-url.defaultZone=http://${
    
    eureka.instance.hostname}:${
    
    server.port}/eureka

配置启动类:
在项目启动类上面使用@EnableEurekaServer,可以将项目作为Spring Cloud的注册中心(启动 Eureka 服务注册中心)
在这里插入图片描述

服务注册中心就搭建好了

2.新建Application Service项目(服务提供方)

2.1 添加依赖

添加了web环境和eureka client依赖

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

2.2 编写配置文件

必须要有应用程序名,因为OpenFeign是通过应用程序名进行调用。

## 端口号
server.port=8081
## 服务名称
spring.application.name=service-demo
## 将服务注册到注册中心 eureka_service 的地址
eureka.client.service-url.defaultZone=http://localhost:8083/eureka/

2.3 新建控制器

controller:


/**
 * @author qzz
 */
@RestController
public class DemoController {
    
    

    @Autowired
    private DemoService demoService;

    /**
     * 无参请求
     * @return
     */
    @RequestMapping("/demo")
    public String demo(){
    
    
        return demoService.demo();
    }
}

serviceImpl:


/**
 * @author qzz
 */
@Service
public class DemoServiceImpl implements DemoService {
    
    


    @Override
    public String demo() {
    
    
        return "demo";
    }
}

2.4 配置启动类

/**
 * @author qzz
 */
@SpringBootApplication
public class ServiceDemoApplication {
    
    

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

}

3.新建Application Client项目(服务调用方)

3.1 添加依赖

比application service项目多了openfeign的依赖

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

3.2 编写配置文件

## 端口号
server.port=8085
## 服务名称
spring.application.name=openfeign-demo
## 将服务注册到注册中心 eureka_service 的地址
eureka.client.service-url.defaultZone=http://localhost:8083/eureka/

3.3 新建OpenFeign接口

OpenFeign接口命名:调用应用程序+Feign

package com.example.openfeigndemo.feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @FeignClient():定义feign客户端
 * service-demo客户端
 * @author qzz
 */
@FeignClient(name = "service-demo")
public interface ServiceDemoFeign {
    
    

    /**
     * 方法要求:
     *    返回值:要对应
     *    方法名:随意
     *    参数:要对应
     *  方法上添加SpringMvc注解
     * @return
     */
    @RequestMapping("/demo")
    String suiyi();
}

注意:

@FeignClient 参数要写调用的Application Service的应用程序名

@RequestMapping中值要和需要调用的控制器方法URL相同

方法返回值要和调用控制器方法返回值相同

方法名称随意,没有要求

FeignClient注解参数:

  • name:指定FeignClient的名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现
  • url: url一般用于调试,可以手动指定@FeignClient调用的地址
  • decode404:当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException
  • configuration: Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract
  • fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口
  • fallbackFactory: 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码
  • path: 定义当前FeignClient的统一前缀

3.4 新建控制器

controller:
在这里插入图片描述
serviceImpl:
注入ServiceDemoFeign,进行远程服务调用:
在实现类中直接注入OpenFeign接口对象即可。没有在启动类上添加@EnableFeignClients时可能会报编译错误。


/**
 *
 * @author qzz
 */
@Service
public class OpenFeignDemoServiceImpl implements OpenFeignDemoService {
    
    

    /**
     * 注入service-demo服务接口(在要使用的地方注入ServiceDemoFeign)
     */
    @Autowired
    private ServiceDemoFeign serviceDemoFeign;

    @Override
    public String demo() {
    
    
        return serviceDemoFeign.suiyi();
    }
}

出现如下红线,原因是Feign在应用层默认是不开启的,
在这里插入图片描述
所以需要在启动类配置开启Feigin。

3.5 新建启动类

package com.example.openfeigndemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @EnableFeignClients:开启OpenFeign注解支持
 */
@SpringBootApplication
@EnableFeignClients
class OpenfeignDemoApplication {
    
    

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

}

4.测试效果

在浏览器中输入http://localhost:8085/demo1,如果打印“demo”说明OpenFeign调用成功
在这里插入图片描述

五、 使用OpenFeign访问带有参数的控制器

1 带有简单数据类型参数

1.1 Application Service项目中添加控制器方法(被调用方)

    /**
     * 有参请求---简单数据类型参数
     * @return
     */
    @RequestMapping("/demo2")
    public String demo2(@RequestParam("name")String name,@RequestParam("age")Integer age){
    
    
        return "name:"+name+",age:"+age;
    }

1.2 Application Client项目中Feign接口添加方法(OpenFeign接口)

@RequestParam注解必须有

如果Feign接口方法参数名和调用控制器参数名相同可以省略@RequestParam的参数

@FeignClient(name = "service-demo")
public interface ServiceDemoFeign {
    
    
    /**
     * 如果Feign接口方法参数名和调用控制器参数名相同可以省略@RequestParam的参数
     * @return
     */
    @RequestMapping("/demo2")
    String demo2(@RequestParam("name")String name123, @RequestParam Integer age);
 }

1.3 Application Client 项目 service、controller代码(调用方)

controller:


    @RequestMapping("/demo2")
    public String demo2(){
    
    
        return openFeignDemoService.demo2("张三",30);
    }

serviceImpl:
在这里插入图片描述

测试结果:

在这里插入图片描述

2 传递请求体数据

使用@RequestBody注解会把对象以aplication/json的形式传参,被调用的服务也需要加上@RequestBody该注解,把收到的json转成对应的对象

2.1 Application Service项目中添加控制器方法(被调用方)


    /**
     * 请求体传参
     * @param user
     * @return
     */
    @PostMapping("/demo3")
    String demo3(@RequestBody User user){
    
    
        return "接收的请求体参数为:"+ JSONObject.toJSONString(user);
    }

2.2 Application Client 项目中Feign接口添加方法(OpenFeign接口)

@FeignClient(name = "service-demo")
public interface ServiceDemoFeign {
    
    
    /**
     * 请求体传参
     * @param user
     * @return
     */
    @PostMapping("/demo3")
    String demo3(@RequestBody User user);
 }

2.3 Application Client 项目 service、controller代码(调用方)

controller:

 @PostMapping("/demo3")
    public String demo3(@RequestBody User user){
    
    
        return openFeignDemoService.demo3(user);
    }

serviceImpl:
在这里插入图片描述
测试结果:
在这里插入图片描述

3 传递数组类型

3.1 Application Service项目中添加控制器方法(被调用方)


    /**
     * 有参请求---数组类型
     * @return
     */
    @RequestMapping("/demo4")
    public String demo4(@RequestParam("ids") String [] ids){
    
    
        return "ids数组:"+JSONObject.toJSONString(ids);
    }

3.2 Application Client 项目中Feign接口添加方法(OpenFeign接口)

@FeignClient(name = "service-demo")
public interface ServiceDemoFeign {
    
    
     /**
     * 数组类型传参
     * @param ids
     * @return
     */
    @RequestMapping("/demo4")
    String demo4(@RequestParam("ids") String[] ids);
 }

3.3 Application Client 项目 service、controller代码(调用方)

controller:


    @RequestMapping("/demo4")
    public String demo4(@RequestParam("ids") String [] ids){
    
    
        return openFeignDemoService.demo4(ids);
    }

serviceImpl:

@Service
public class OpenFeignDemoServiceImpl implements OpenFeignDemoService {
    
    
    
    /**
     * 注入service-demo服务接口(在要使用的地方注入ServiceDemoFeign)
     */
    @Autowired
    private ServiceDemoFeign serviceDemoFeign;
    
    /**
     * 数组类型传参
     * @param ids
     * @return
     */
    @Override
    public String demo4(String[] ids) {
    
    
        return serviceDemoFeign.demo4(ids);
    }
}

测试结果:
在这里插入图片描述

4 既包含请求体数据,又包含普通表单数据

请求体数据必须有@RequestBody

4.1 Application Service项目中添加控制器方法(被调用方)


    /**
     * 有参请求---请求体数据、普通表单数据
     * @return
     */
    @RequestMapping("/demo5")
    public String demo5(@RequestBody User user,String address){
    
    
        return "id:"+user.getId()+",name:"+user.getName()+",age:"+user.getAge()+",address:"+address;
    }

4.2 Application Client 项目中Feign接口添加方法(OpenFeign接口)

请求体数据必须有@RequestBody,普通表单必须有@RequestParam

@FeignClient(name = "service-demo")
public interface ServiceDemoFeign {
    
    
      /**
     * 有参请求---请求体数据、普通表单数据
     * @return
     */
    @PostMapping("/demo5")
    String demo5(@RequestBody User user, @RequestParam("address") String address);
 }

4.3 Application Client 项目 service、controller代码(调用方)

controller:


    /**
     * 有参请求---请求体数据、普通表单数据
     * @return
     */
    @PostMapping("/demo5")
    public String demo5(@RequestBody User user,@RequestParam("address") String address){
    
    
        return openFeignDemoService.demo5(user, address);
    }

serviceImpl:

@Service
public class OpenFeignDemoServiceImpl implements OpenFeignDemoService {
    
    
    
    /**
     * 注入service-demo服务接口(在要使用的地方注入ServiceDemoFeign)
     */
    @Autowired
    private ServiceDemoFeign serviceDemoFeign;
   
    /**
     * 有参请求---请求体数据、普通表单数据
     * @return
     */
    @Override
    public String demo5(User user, String address) {
    
    
        return serviceDemoFeign.demo5(user,address);
    }
}

测试结果:
在这里插入图片描述

六、源码下载

可点击此处进行下载

猜你喜欢

转载自blog.csdn.net/qq_26383975/article/details/127924284
今日推荐