Feign的使用指导
摘要:本文介绍了如何在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_id为 user的配置 请谨慎修改。
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

浙公网安备 33010602011771号