Feign在ECP项目中的使用指导

369人浏览 / 0人评论

摘要:本文介绍了如何在ECP项目中使用Feign进行微服务开发。我们从基础配置开始,讨论了如何使用Spring Cloud OpenFeign结合ECP 工程,并详细解释了Feign的默认配置。然后,我们重点介绍了单个Feign服务如何创建。通过学习本文,您将掌握如何高效使用Feign构建可靠的微服务通信。

1. 引言

随着微服务架构的兴起,服务之间的通信变得至关重要。Feign是一个声明式、模板化的HTTP客户端,用于简化服务之间的通信。在ECP项目中,我们可以使用Spring Cloud OpenFeign库来轻松实现服务间的调用。

2. 基础使用

2.1 Feign基础使用

在ECP项目中,我们可以利用Spring MVC的注解和特性来定义Feign接口。通过在接口上添加@FeignClient注解,我们可以指定要调用的服务名称、配置类、请求拦截器等。例如:

2.2 ECP工程的Feign默认配置

在ECP项目中,我们可以通过在配置文件中添加Feign的默认配置来自定义Feign客户端的行为。例如,在application.yml文件中可以配置如下内容:

通过以上配置,我们设置基本配置好了feign。

3. 具体示例

使用场景:我们需要在 ecp-desk 的服务中调用 ecp-provider-feign 中接口,分两端 服务端 和 消费端

ecp-provider-feign 服务端代码如下

package cn.histo.ecp.provider.controller;

import cn.histo.provider.feign.entity.ProvideNotice;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tenant.annotation.NonDS;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import java.util.concurrent.TimeUnit;

/**
* @author Verite
* @date 2023/6/9 0:04
*/
@NonDS
@ApiIgnore()
@RestController
@Slf4j
@RequestMapping("client/provider")
public class ProviderController {

@Value("${server.port}")
String port;

/**
* 默认调用
*/
@GetMapping("index")
public String index(@RequestParam String param) throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(3000);
log.info(param);
return "端口:" + port + "; 参数:" + param;
}

/**
* 使用 PathVariable 注解
*
* @param current 当前页
* @param size 每页显示条数
* @return PathVariable 的参数
*/
@GetMapping("usePathVariable/{current}/{size}")
public String usePathVariable(@PathVariable("current") Integer current, @PathVariable("current") Integer size) {
return "使用 PathVariable 注解 。当前页:" + current + "; 每页显示条数:" + size;
}

/**
* 使用 RequestParam 注解
*
* @param current 当前页
* @param size 每页显示条数
* @return RequestParam 的参数
*/
@GetMapping("useRequestParam")
public String useRequestParam(@RequestParam Integer current, @RequestParam Integer size) {
return "使用 RequestParam 注解 。当前页:" + current + "; 每页显示条数:" + size;
}

/**
* 使用 RequestParam 注解
*
* @param notice 参数
* @return notice 的参数
*/
@GetMapping("useBody")
public ProvideNotice useBody(@RequestBody ProvideNotice notice) {
return notice;
}
}
 

ecp-desk 消费端 的 feign 的使用 如下步骤

A,在启动器中加入 feign的 注解 @EnableFeignClients({"org.springblade", "cn.histo"})

B,我们将在IUserFeignClient 列举 四种方式 来说明如何使用feign,以及针对 IUserFeignClient  的独立服务配置,和服务失败进行处理的方式

针对 IUserFeignClient必须,feign客户端

UserConfiguration非必须,需要单独配置参数则创建) 

IUserFeignClientFallback非必须,此服务需要有服务失败进行单独处理则创建)

在ECP 工程中,文件的创建位置 以及 使用 如下图:

C,  以下是 IUserFeignClient 文件 ,创建常用的四种创建方式。

package cn.histo.desk.feign;

import cn.histo.desk.feign.config.UserConfiguration;
import cn.histo.provider.feign.entity.ProvideNotice;
import io.swagger.annotations.ApiParam;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

/**
* IUserFeignClient接口:这是一个定义Feign客户端的接口。它包含了一些需要调用的远程服务的方法。
*
* @author Chill
*/
//@FeignClient(必须) 这是一个Feign客户端的注解,用于标识该接口是一个Feign客户端接口。
@FeignClient(
contextId = "user" // contextId(非必须)是该客户端的上下文ID
, value = "blade-provider-feign" // value | name(必须 ) 推荐使用name
, fallback = IUserFeignClientFallback.class // 熔断处理
, configuration = UserConfiguration.class // (非必须) 是指定的Feign客户端配置类
)
public interface IUserFeignClient {

/**
* 默认是以 /client 开头
*/
String API_PREFIX = "/client/provider/";

/**
* 默认接口 第一种使用方式
*/
String INDEX = "index";

/**
* 第二种使用 usePathVariable 注解的方式
*/
String USE_PATH_VARIABLE = "/usePathVariable/{current}/{size}";

/**
* 第三种使用 useRequestParam 注解的方式
*/
String USE_REQUEST_PARAM = "useRequestParam";

/**
* 第四种使用 RequestBody 注解的方式
*/
String USE_BODY = "useBody";

/**
* 默认调用
*/
@GetMapping(API_PREFIX + INDEX)
void index();

/**
* 使用 PathVariable 注解
*
* @param current 当前页
* @param size 每页显示条数
* @return PathVariable 的参数
*/
@GetMapping(API_PREFIX + USE_PATH_VARIABLE)
String usePathVariable(@ApiParam(value = "当前页") @PathVariable Integer current, @ApiParam(value = "每页显示条数") @PathVariable Integer size);

/**
* 使用 RequestParam 注解
*
* @param current 当前页
* @param size 每页显示条数
* @return RequestParam 的参数
*/
@GetMapping(API_PREFIX + USE_REQUEST_PARAM)
String useRequestParam(@RequestParam Integer current, @RequestParam Integer size);

/**
* 使用 Body 注解
*
* @param provideNotice 提示类
* @return 返回 Notice
*/
@PostMapping(API_PREFIX + USE_BODY)
ProvideNotice useBody(@RequestBody ProvideNotice provideNotice);
}
 

D,以下是 UserConfiguration文件 ,针对 IUserFeignClient  服务单独配置。 

package cn.histo.desk.feign.config;

import cn.histo.desk.feign.config.requestInterceptor.AuthInterceptor;
import cn.histo.desk.feign.config.coder.FastJsonDecoder;
import cn.histo.desk.feign.config.coder.FastJsonEncoder;
import feign.codec.Decoder;
import feign.codec.Encoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.encoding.FeignClientEncodingProperties;
import org.springframework.context.annotation.Bean;

/**
* @author Verite
* @date 2023/6/1 17:24
*/
@Slf4j
public class UserConfiguration {
}

E,以下是 IUserFeignClientFallback  文件 ,针对 IUserFeignClient  服务失败进行处理。 

package cn.histo.desk.feign;

import cn.histo.provider.feign.entity.ProvideNotice;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;

/**
* 远程调用失败处理类
*
* @author lihao
*/
@Component
@Slf4j
public class IUserFeignClientFallback implements IUserFeignClient {

/**
* 默认调用
*/
@Override
public void index() {

}

/**
* 使用 PathVariable 注解
*
* @param current 当前页
* @param size 每页显示条数
* @return PathVariable 的参数
*/
@Override
public String usePathVariable(Integer current, Integer size) {
return "User fallback : usePathVariable";
}

/**
* 使用 RequestParam 注解
*
* @param current 当前页
* @param size 每页显示条数
* @return RequestParam 的参数
*/
@Override
public String useRequestParam(Integer current, Integer size) {
return "User fallback : useRequestParam";
}

/**
* 使用 Body 注解
*
* @param provideNotice 提示类
* @return 返回 Notice
*/
@Override
public ProvideNotice useBody(@RequestBody ProvideNotice provideNotice) {
provideNotice.setContent("fallback : useBody");
return provideNotice;
}
}
 

F,   使用的一种方式


package cn.histo.desk.controller;

import cn.histo.desk.feign.IOrderFeignClient;
import cn.histo.desk.feign.IUserFeignClient;
import cn.histo.provider.feign.entity.ProvideNotice;
import cn.histo.provider.feign.feign.IProviderNoticeClient;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.tenant.annotation.NonDS;
import org.springblade.core.tool.api.R;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
* 控制器
*
* @author Verite
*/
@Slf4j
@NonDS
@RestController
@RequestMapping("normalFeign")
@AllArgsConstructor
@Api(value = "feign 远程调用示例", tags = "feign 调用示例")
public class DemoFeignController extends BladeController {

private final IUserFeignClient userFeignClient;

/**
* 默认调用
*/
@GetMapping("/userIndex")
@ApiOperationSupport(order = 1)
@ApiOperation(value = "默认调用", notes = "index")
public R<Object> userIndex(@RequestParam String param, @RequestParam String base) {
String res = userFeignClient.index(param, base);
return R.success("user index" + res);
}

/**
* 使用 PathVariable
*/
@GetMapping("/usePathVariable/{current}/{size}")
@ApiOperationSupport(order = 2)
@ApiOperation(value = "usePathVariable", notes = "使用 RequestParam")
public R<String> usePathVariable(@ApiParam(value = "当前页") @PathVariable Integer current, @ApiParam(value = "每页显示条数") @PathVariable Integer size) {
String page = userFeignClient.usePathVariable(current, size);
return R.data(page);
}

/**
* 使用 RequestParam
*/
@GetMapping("userRequestParam")
@ApiOperationSupport(order = 3)
@ApiOperation(value = "userRequestParam", notes = "使用 userRequestParam")
public R<String> useRequestParam(@RequestParam Integer current, @RequestParam Integer size) {
String page = userFeignClient.useRequestParam(current, size);
return R.data(page);
}

/**
* 使用 RequestBody
*/
@PostMapping("useBody")
@ApiOperationSupport(order = 4)
@ApiOperation(value = "useBody", notes = "使用 body")
public R<ProvideNotice> useBody(@RequestBody ProvideNotice provideNotice) {
ProvideNotice resProvideNotice = userFeignClient.useBody(provideNotice);
return R.data(resProvideNotice);
}

}
 

4. 注意事项

在本节中,我们将列举一些开发者常见的问题,并提供具体的解决方法。这些问题可能涉及Feign的配置、使用过程中的错误、性能优化等方面。我们将通过实际案例和解决方案来帮助开发者更好地应对这些问题。

1,在ecp-desk中 创建 IUserFeignClient.usePathVarable(@PathVarable) 等等接口时,类似 @PathVarable 等等缺失,远程调用会找不到 ecp-provider-feign的对应接口。

2,yml配置中 feign.client.config.default 是全局服务的配置 ,请谨慎修改。

3,yml配置中 feign.client.config.user 是对以上代码中的 IUserFeignClient文件 →注解@FeignClients context_iduser的配置 请谨慎修改。

4,使用hystrix 熔断生效 需要三步 :1>启动器要加载 @EnableHystrix 注解 ;2> yml配置文件开始 feign.circuitbreaker.enabled: true ;3> 在@FeignClients 中的fallback参数加载IUserFeignClientFallback 文件并实现。

5,UserConfiguration 文件如果使用了 @Configuration 或者 @Componet,其中的拦截器会全局生效,请谨慎使用 。

本文详细介绍了使用Feign简化微服务开发的方法。我们从基础配置开始,探讨了Spring Cloud OpenFeign和ECP工程的集成,并介绍了Feign的默认配置。然后,我们重点讲解了单个Feign服务如何在ECP中的使用。通过学习本文,您将掌握使用Feign构建可靠的微服务通信的技巧和最佳实践。

希望本文对正在使用Feign进行微服务开发的开发者提供了实用的指导和建议。通过合理配置和使用Feign,您可以极大地简化微服务通信的开发过程,提高系统的可靠性和可扩展性。

参考资料

nacos官方介绍 https://nacos.io/zh-cn/docs/v2/quickstart/quick-start.html

feign官方介绍 https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#spring-cloud-feign

Hystrix官方介绍 https://www.kancloud.cn/ur_champaign/hytrix/840124

feign 简介和使用 https://zhuanlan.zhihu.com/p/416699563

feign配置原理讲解 https://blog.csdn.net/weixin_42039228/article/details/123714356

Feign的使用及原理剖析https://blog.csdn.net/weixin_50117915/article/details/128236218

 

全部评论