OpenFeign 接入 SCA
参考:https://www.mengshuo.top/archives/springcloudnetflix#feign
demo地址:https://duangouyu.coding.net/p/demo/d/SCA/git/tree/openfeign
由于 Feign 也进入了维护, 所以就有了 OpenFeign 这个代替品
Feign 和 OpenFeign 的区别
Feign | OpenFeign |
---|---|
Feign 是 Springcloud 组件中的一个轻量级 Restful 的 HTTP 服务客户端, Feign 内置了 Ribbon, 用来做客户端负载均衡, 去调用服务注册中心的服务. Feign 的使用方式是: 使用 Feign 的注解定义接口, 调用这个接口, 就可以调用服务注册中心的服务. | OpenFeign 是 springcloud 在 Feign 的基础上支持了 SpringMVC 的注解, 如@RequestMapping 等等. OpenFeign 的@FeignClient 可以解析 SpringMVC 的@RequestMapping 注解下的接口, 并通过动态代理的方式产生实现类, 实现类中做负载均衡并调用其他服务. |
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency> | <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> |
OpenFeign 的使用:
微服务调用接口 + @FeignClient 注解
需要注意, @RequesMapping 不能在类名上与@FeignClient 同时使用
如果只有服务消费者添加配置就可以了,服务提供者不调用其他服务可以不用配置,因为底层毕竟还是发起 http 请求
整合 OpenFegin
添加依赖
<!-- 公共依赖 -->
<dependencies>
<!-- 自定义异常处理 -->
<dependency>
<groupId>top.mengshuo</groupId>
<artifactId>base-exception</artifactId>
</dependency>
<!-- 解决 bootstrap.yml 不生效问题 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 端点监控 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Nacos注册中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Nacos配置中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- base service -->
<dependency>
<groupId>top.mengshuo</groupId>
<artifactId>base-service</artifactId>
</dependency>
<!-- open feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- loadbalancer -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!-- sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- nacos 持久化sentinel规则 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
添加注解启用 OpenFeign
添加 @EnableFeignClients 注解
package top.mengshuo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import java.util.Arrays;
/**
* 服务消费者application
*
* @author mengshuo
* @since 2021-11-17
*/
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class ConsumerServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerServiceApplication.class, args);
}
}
配置文件启用 Sentinel 和 OpenFeign 的集成
# 启用 sentinel 和 openfeign 集成
feign:
sentinel:
enabled: true
代码
服务消费者
-
添加一个服务调用类
package top.mengshuo.feign; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import top.mengshuo.common.exception.entity.RestResponse; import top.mengshuo.feign.fallback.ProviderServiceFallback; /** * OpenFeign 声明式客户端 * * @author mengshuo * @since 2021-12-12 */ @FeignClient(name = "provider-service", fallback = ProviderServiceFallback.class, path = "/provider") public interface ProviderService { /** * OpenFeign 调用服务提供者 * * @param name 名称 * @return res */ @PostMapping("/hello") RestResponse<?> sayHello(@RequestParam("name") String name); }
-
服务降级类
package top.mengshuo.feign.fallback; import org.springframework.stereotype.Component; import top.mengshuo.common.exception.entity.RestResponse; import top.mengshuo.feign.ProviderService; /** * @author mengshuo * @since 2021-11-23 */ @Component public class ProviderServiceFallback implements ProviderService { @Override public RestResponse<?> sayHello(String name) { return RestResponse.failed().message("OpenFeign 降级"); } }
-
Controller 中调用
package top.mengshuo.controller; import lombok.extern.log4j.Log4j2; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import top.mengshuo.common.exception.entity.RestResponse; import top.mengshuo.feign.ProviderService; import javax.annotation.Resource; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; /** * @author mengshuo * @since 2021-11-17 */ @Log4j2 @RestController @RequestMapping("/consumer") public class ConsumerController { @Resource private ProviderService providerService; @GetMapping("/hello") public RestResponse<?> hello(String name) { log.info("处理时间:" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SS"))); return this.providerService.sayHello(name); } }
服务提供者
-
添加 service
package top.mengshuo.service.impl; import com.alibaba.csp.sentinel.annotation.SentinelResource; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import top.mengshuo.service.ProviderService; /** * @author mengshuo * @since 2021-11-17 */ @SentinelResource @Service public class ProviderServiceImpl implements ProviderService { @Value("${sys.desc}") private String desc; /** * hello * * @param name name * @return res */ @Override public String sayHello(String name) { return "hello:" + name + " >>> " + desc; } }
-
添加 Controller
当没有 name 参数时 报错 触发服务降级
package top.mengshuo.controller; import org.springframework.util.ObjectUtils; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import top.mengshuo.common.exception.entity.RestResponse; import top.mengshuo.service.ProviderService; import javax.annotation.Resource; /** * @author mengshuo * @since 2021-12-12 */ @RestController @RequestMapping("/provider") public class ProviderController { @Resource private ProviderService providerService; @PostMapping("/hello") public RestResponse<?> sayHello(String name) { if (ObjectUtils.isEmpty(name)) { throw new RuntimeException(); } return RestResponse.success().data(this.providerService.sayHello(name)); } }
测试
-
正常调用
-
缺少参数的调用