织梦网站怎样做seo,wordpress 分页标题,充值网站怎么做的,简单的网页页面设计图片SpringCloudAlibaba OpenFeign 在前面#xff0c;我们使用Nacos服务注册发现后#xff0c;服务远程调用可以使用RestTemplateRibbon或者OpenFeign调用。实际开发中很少使用RestTemplate这种方式进行调用服务#xff0c;每次调用需要填写地址#xff0c;还要配置各种的参数我们使用Nacos服务注册发现后服务远程调用可以使用RestTemplateRibbon或者OpenFeign调用。实际开发中很少使用RestTemplate这种方式进行调用服务每次调用需要填写地址还要配置各种的参数很麻烦。使用OpenFeign的方式就可以解决这种问题。 那么说起了OpenFeign就需要提及一下Feign了因为OpenFeign是Feign的增强版。Feign是一个轻量级Restful HTTP服务客户端内置ribbon用作客户端负载均衡使用Feign时只需要定义一个接口加上注解符合面向接口的编程习惯使远程调用服务更加容易。
OpenFeign是对Feign的进一步封装使其支持Spring MVC的标准注解和HttpMessageConverters如RequestMapping等。
集成OpenFeign 在消费者客户端中集成OpenFeign 导入依赖
dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-openfeign/artifactId
/dependency在bootstrap.yml中增加OpenFeign对Sentinel的支持增加feign.sentinel.enabled配置项
server:port: 9001
spring:application:name: consumer # 应用名cloud:nacos:discovery:server-addr: localhost:8848 # nacos服务地址sentinel:transport:port: 8719 # 启动http server并且该服务与Sentinel仪表板进行交互使sentinel可以控制应用若端口占用则87191依次扫描dashboard: 127.0.0.1:8080 # 仪表版访问地址
feign: # 增加对sentinel的支持sentinel:enabled: true这里说一下如果不加feign.sentinel.enabledtrue的配置那么在FeignClient中定的fallback属性定义的异常、限流等自定义的处理逻辑不会生效
在主启动类上加入EnableFeignClients注解标记为启用OpenFeign具体如下
SpringBootApplication
EnableDiscoveryClient
EnableFeignClients
public class Consumer {public static void main(String[] args) {SpringApplication.run(Consumer.class, args);}
}笔者这里再提一句假如是分布式项目将openfeign抽取为一个单独的服务模块时可能出现我openfeign中的包名和其他模块不一致可以自己声明FeignClient组件的basePackages设置一下FeignClient的扫描路径。示例如下
SpringBootApplication
EnableDiscoveryClient
EnableFeignClients(basePackages com.alibaba.provider.feigns)
public class Consumer {public static void main(String[] args) {SpringApplication.run(Consumer.class, args);}
}
增加一个FeignClient的客户端
/*** provider : 表示调用的生产者服务名* fallback:异常时进入的处理类*/
FeignClient(value provider, fallback OpenFeignTestServiceFallback.class)
public interface OpenFeignTestService {RequestMapping(value /openFeignProviderTest, method RequestMethod.GET)public String openFeignProviderTest();}创建OpenFeignTestServiceFallback做fallback处理
Component
public class OpenFeignTestServiceFallback implements OpenFeignTestService{Overridepublic String openFeignProviderTest() {return 我是兜底方法;}
}创建controller做个接口方便调用
RestController
public class OpenFeignTestController {Resourceprivate OpenFeignTestService openFeignTestService;RequestMapping(/openFeignTest)public String openFeignTest() {return openFeignTestService.openFeignProviderTest();}}在服务生产者方提供接口 RestController
public class OpenFeignProviderTest {RequestMapping(/openFeignProviderTest)public String openFeignProviderTest() {return OpenFeignTestController#openFeignProviderTest RandomUtils.nextInt(0, 1000);}}测试接口 使用curl或浏览器都行调用服务消费者方的/openFeignTest接口测试
curl http://localhost:9001/openFeignTest
OpenFeignTestController#openFeignProviderTest748代码优化一下
在FeignClient注解中value属性填写的是服务提供者的服务名称这么把值直接写死是不合适的假如服务提供者名称变了那么这里写的就需要修改而且如果用的地方比较多的情况下需要到处修改。如何解决呢
把服务名用一个单独的类定义静态常量使用配置文件方式使用表达式获取即可
定义静态常量类就不再演示使用配置文件方式
provider:name: provider在FeignClient客户端使用表达式获取
FeignClient(value ${provider.name}, fallback OpenFeignTestServiceFallback.class)结合sentinel规则使用
不管是RestTemplateRibbon还是OpenFeign的远程调用都是支持Sentinel的到sentinel面板中配置资源流控规则
注意sentinel是懒加载方式需要先去调用一次接口才能在控制台添加规则
在sentinel面板新增openFeignProviderTest流控规则阈值类型QPS单机阈值1 欧克我们对服务端的/openFeignProviderTest做了限流那么试试多次连续访问客户端接口试试。 可以看到有请求会进入到fallback降级中。 那么对于异常该怎么处理呢 修改服务端接口代码设置一个异常进行测试接口 欧克发现服务端如果是出现了异常仍然会进入客户端的fallback处理中是不是非常奈斯。
那么同样的假如服务器进入宕机状态会如何关掉服务端试试。 行的一样可以进入到fallback处理中。
实现负载均衡
OpenFeign也具有负载均衡的功能多个服务端时采用对应的算法寻找一个服务端进行请求。
下面服务端将输出当前项目的端口号并且再新建一个服务端的项目
RestController
public class OpenFeignProviderTest {Value(${server.port})private Integer port;RequestMapping(/openFeignProviderTest)public String openFeignProviderTest() {return OpenFeignTestController#openFeignProviderTest port;}}再新建一个项目端口为8003即可。
server:port: 8002
...多余部分省略server:port: 8003
...多余部分省略项目启动nacos中可以发现服务端两个实例 多次调用客户端接口看结果 依次轮询方式请求服务。
OpenFeign的超时配置
2020版本以前的OpenFeign的默认等待接口返回数据的时间是1s超过1秒就报错如果有fallback那么执行fallback的处理。
2020版本后源码如下
public Options() {//10L: connectTimeout//60L: readTimeoutthis(10L, TimeUnit.SECONDS, 60L, TimeUnit.SECONDS, true);
}connectTimeout是10sreadTimeout是60s
普通接口是没有问题的但是如果是一些耗时业务执行过程中一定是大于1s的不太合理。
那么OpenFeign提供了超时的配置。消费者bootstrap.yml文件中增加超时配置
feign.client.config.default.connectTimeout:建立连接的超时时间feign.client.config.default.readTimeout:建立连接后从服务器读取资源所用时间的超时时间配置
server:port: 9001
spring:application:name: consumer # 应用名cloud:nacos:discovery:server-addr: localhost:8848 # nacos服务地址sentinel:transport:port: 8719 # 启动http server并且该服务与Sentinel仪表板进行交互使sentinel可以控制应用若端口占用则87191依次扫描dashboard: 127.0.0.1:8080 # 仪表版访问地址
feign:sentinel:enabled: trueclient:config:default:connectTimeout: 2000 # 建立连接超时时间readTimeout: 2000 # 读取资源超时时间RequestMapping(/openFeignProviderTest)
public String openFeignProviderTest() throws InterruptedException {Thread.sleep(5000);return OpenFeignTestController#openFeignProviderTest port;
}这里故意睡眠5s超时时间是2s那么一定是超时了会进入fallback.
时间调长点试试
..
feign:sentinel:enabled: trueclient:config:default:connectTimeout: 7000 # 建立连接超时时间readTimeout: 7000 # 读取资源超时时间没问题
OpenFeign的日志
为方便查找异常一般在本地开发环境中把OpenFeign远程调用接口的日志详情打印出来。
在服务消费者bootstrap.yml文件新增日志级别的配置新增配置项logging.level.声明接口的包名完整配置如下
server:port: 9001
spring:application:name: consumer # 应用名cloud:nacos:discovery:server-addr: localhost:8848 # nacos服务地址sentinel:transport:port: 8719 # 启动http server并且该服务与Sentinel仪表板进行交互使sentinel可以控制应用若端口占用则87191依次扫描dashboard: 127.0.0.1:8080 # 仪表版访问地址
feign:sentinel:enabled: trueclient:config:default:connectTimeout: 5000 # 建立连接超时时间readTimeout: 5000 # 读取资源超时时间logging:level:com.alibaba.provider.feigns: debug # 打印自己项目中com.alibaba.provider.feigns包的日志级别是debug级别然后在java中创建一个配置类
Configuration
public class OpenFeignLoggerConfiguration {Beanpublic Logger.Level openFeignLoggerLevel() {return Logger.Level.FULL; // FULL日志级别}}OpenFeign日志有以下几个级别 NONE:无记录默认的BASIC:只记录请求方法和url及响应状态代码和执行时间HEADERS:只记录基本信息及请求和响应头FULL:记录请求和响应的头文件正文和元数据信息最全
配置后日之后如下 信息非常完整方便排错。
请求和响应压缩
OpenFeign支持通过简单配置实现请求和响应进行gzip压缩提高数据传输的效率。
开启压缩可以有效节约网络资源但是在压缩和解压过程中会增加CPU的压力最好把最小请求长度参数调大一些。
向bootstrap.yml文件中增加参数配置(服务消费者端)
server:port: 9001
spring:application:name: consumer # 应用名cloud:nacos:discovery:server-addr: localhost:8848 # nacos服务地址sentinel:transport:port: 8719 # 启动http server并且该服务与Sentinel仪表板进行交互使sentinel可以控制应用若端口占用则87191依次扫描dashboard: 127.0.0.1:8080 # 仪表版访问地址
feign:sentinel:enabled: trueclient:config:default:connectTimeout: 5000 # 建立连接超时时间readTimeout: 5000 # 读取资源超时时间compression:request:enabled: true # 请求压缩启用mime-types: text/xml, application/xml, application/json # 要压缩的类型min-request-size: 2048 # 最小请求长度 单位:字节response:enabled: true # 响应压缩启用logging:level:com.alibaba.provider.feigns: debug # 打印com.alibaba.provider.feigns包的日志级别是debug级别压缩后可以看下日志情况 OpenFeign的参数传递 简单参数传递 服务端接口
PostMapping(/sampleParamsProviderTest)
public String sampleParamsProviderTest(RequestParam(name) String name, RequestParam(id) Integer id) {return OpenFeignProviderTest# sampleParamsProviderTest# port id id ,name name;
}消费者OpenFeign
FeignClient(value ${provider.name}, fallback OpenFeignTestServiceFallback.class)
public interface OpenFeignTestService {PostMapping(/sampleParamsProviderTest)public String sampleParamsProviderTest(RequestParam(name) String name, RequestParam(id) Integer id);}消费者fallback
Component
public class OpenFeignTestServiceFallback implements OpenFeignTestService {Overridepublic String sampleParamsProviderTest(String name, Integer id) {return 我是兜底方法 name id;}
}消费者提供一个接口做测试
GetMapping(/sampleParamsProviderTest)
public String sampleParamsProviderTest() {return openFeignTestService.sampleParamsProviderTest(gangge, 1);
}SpringQueryMap对象传递 那么先创建一个要传递的对象服务提供者和消费者共用
public class Params {private Integer id;private String name;.../getter、setter方法
}服务提供者创建一个给消费者调用的接口
GetMapping(/springQueryMapProviderTest)
public String springQueryMapProviderTest(Params params) {return OpenFeignProviderTest# sampleParamsProviderTest# port id params.getId() ,name params.getName();
}消费者OpenFeign
GetMapping(/springQueryMapProviderTest)
public String springQueryMapProviderTest(SpringQueryMap Params params);消费者fallback
Override
public String springQueryMapProviderTest(Params params) {return 我是兜底方法 params.getId() params.getName();
}消费者接口
GetMapping(/springQueryMapTest)
public String springQueryMapTest() {Params params new Params();params.setId(1);params.setName(gangge);return openFeignTestService.springQueryMapProviderTest(params);
}结果 复杂对象传递 对象套对象的情况准备一个ComplexObject和Result对象(提供者和消费者都需要创建)
ComplexObject
public class ComplexObject {private Params params;public Params getParams() {return params;}public void setParams(Params params) {this.params params;}
}Result
public class Result {private Integer code;private String describe;public Integer getCode() {return code;}public void setCode(Integer code) {this.code code;}public String getDescribe() {return describe;}public void setDescribe(String describe) {this.describe describe;}
}在服务提供方编写接口接受消费者调用后返回Result对象
PostMapping(/complexObjectProviderTest)
public Result complexObjectProviderTest(RequestBody ComplexObject complexObject) {Result result new Result();result.setCode(200);result.setDescribe(#complexObjectProviderTest complexObject.getParams().getName() complexObject.getParams().getId());return result;
}消费者声明客户端接口和fallback操作
PostMapping(/complexObjectProviderTest)
public Result complexObjectProviderTest(RequestBody ComplexObject complexObject);Override
public Result complexObjectProviderTest(ComplexObject complexObject) {return null;
}返回Result对象**
PostMapping(/complexObjectProviderTest)
public Result complexObjectProviderTest(RequestBody ComplexObject complexObject) {Result result new Result();result.setCode(200);result.setDescribe(#complexObjectProviderTest complexObject.getParams().getName() complexObject.getParams().getId());return result;
}消费者声明客户端接口和fallback操作
PostMapping(/complexObjectProviderTest)
public Result complexObjectProviderTest(RequestBody ComplexObject complexObject);Override
public Result complexObjectProviderTest(ComplexObject complexObject) {return null;
}复杂对象时RequestBody注解完全可以但是只能有一个RequestBody的参数