博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring Cloud Alibaba Sentinel对Feign的支持
阅读量:6682 次
发布时间:2019-06-25

本文共 5044 字,大约阅读时间需要 16 分钟。

Spring Cloud Alibaba Sentinel 除了对 RestTemplate 做了支持,同样对于 Feign 也做了支持,如果我们要从 Hystrix 切换到 Sentinel 是非常方便的,下面来介绍下如何对 Feign 的支持以及实现原理。

集成 Feign 使用

spring-cloud-starter-alibaba-sentinel 的依赖还是要加的,如下:

org.springframework.cloud
spring-cloud-starter-alibaba-sentinel
0.2.1.RELEASE
复制代码

需要在配置文件中开启 sentinel 对 feign 的支持:

feign.sentinel.enabled=true复制代码

然后我们定义自己需要调用的 Feign Client:

@FeignClient(name = "user-service", fallback = UserFeignClientFallback.class)public interface UserFeignClient {		@GetMapping("/user/get")	public String getUser(@RequestParam("id") Long id);	}复制代码

定义 fallback 类 UserFeignClientFallback:

@Componentpublic class UserFeignClientFallback implements UserFeignClient {	@Override	public String getUser(Long id) {		return "fallback";	}}复制代码

测试代码:

@Autowiredprivate UserFeignClient userFeignClient;@GetMapping("/testFeign")public String testFeign() {	return userFeignClient.getUser(1L);}复制代码

你可以将这个 Client 对应的 user-service 停掉,然后就可以看到输出的内容是 "fallback"

如果要对 Feign 调用做限流,资源名称的规则是精确到接口的,以我们上面定义的接口来分析,资源名称就是GET:

原理分析

首先看SentinelFeignAutoConfiguration中如何自动配置:

@Bean@Scope("prototype")@ConditionalOnMissingBean@ConditionalOnProperty(name = "feign.sentinel.enabled")public Feign.Builder feignSentinelBuilder() {	return SentinelFeign.builder();}复制代码

@ConditionalOnProperty 中 feign.sentinel.enabled 起了决定性作用,这也就是为什么我们需要在配置文件中指定 feign.sentinel.enabled=true

接下来看 SentinelFeign.builder 里面的实现:

build方法中重新实现了super.invocationHandlerFactory方法,也就是动态代理工厂,构建的是InvocationHandler对象。

build中会获取Feign Client中的信息,比如fallback,fallbackFactory等,然后创建一个SentinelInvocationHandler,SentinelInvocationHandler继承了InvocationHandler。

@Overridepublic Feign build() {	super.invocationHandlerFactory(new InvocationHandlerFactory() {		@Override		public InvocationHandler create(Target target,				Map
dispatch) { // 得到Feign Client Bean Object feignClientFactoryBean = Builder.this.applicationContext .getBean("&" + target.type().getName()); // 得到fallback类 Class fallback = (Class) getFieldValue(feignClientFactoryBean, "fallback"); // 得到fallbackFactory类 Class fallbackFactory = (Class) getFieldValue(feignClientFactoryBean, "fallbackFactory"); // 得到调用的服务名称 String name = (String) getFieldValue(feignClientFactoryBean, "name"); Object fallbackInstance; FallbackFactory fallbackFactoryInstance; // 检查 fallback 和 fallbackFactory 属性 if (void.class != fallback) { fallbackInstance = getFromContext(name, "fallback", fallback, target.type()); return new SentinelInvocationHandler(target, dispatch, new FallbackFactory.Default(fallbackInstance)); } if (void.class != fallbackFactory) { fallbackFactoryInstance = (FallbackFactory) getFromContext(name, "fallbackFactory", fallbackFactory, FallbackFactory.class); return new SentinelInvocationHandler(target, dispatch, fallbackFactoryInstance); } return new SentinelInvocationHandler(target, dispatch); } // 省略部分代码 }); super.contract(new SentinelContractHolder(contract)); return super.build();}复制代码

SentinelInvocationHandler中的invoke方法里面进行熔断限流的处理。

// 得到资源名称(GET:http://user-service/user/get)String resourceName = methodMetadata.template().method().toUpperCase() + ":"					+ hardCodedTarget.url() + methodMetadata.template().url();Entry entry = null;try {	ContextUtil.enter(resourceName);	entry = SphU.entry(resourceName, EntryType.OUT, 1, args);	result = methodHandler.invoke(args);}catch (Throwable ex) {	// fallback handle	if (!BlockException.isBlockException(ex)) {		Tracer.trace(ex);	}	if (fallbackFactory != null) {		try {            // 回退处理			Object fallbackResult = fallbackMethodMap.get(method)					.invoke(fallbackFactory.create(ex), args);			return fallbackResult;		}		catch (IllegalAccessException e) {			// shouldn't happen as method is public due to being an interface			throw new AssertionError(e);		}		catch (InvocationTargetException e) {			throw new AssertionError(e.getCause());		}	}    // 省略.....}复制代码

总结

总的来说,这些框架的整合都有相似之处,前面讲RestTemplate的整合其实和Ribbon中的@LoadBalanced原理差不多,这次的Feign的整合其实我们从其他框架的整合也是可以参考出来的,最典型的就是Hystrix了。

我们想下Hystrix要对Feign的调用进行熔断处理,那么肯定是将Feign的请求包装了HystrixCommand。同样的道理,我们只要找到Hystrix是如何包装的,无非就是将Hystrix的代码换成Sentinel的代码而已。

InvocationHandlerFactory是用于创建动态代理的工厂,有默认的实现,也有Hystrix的实现feign.hystrix.HystrixFeign。

Feign build(final FallbackFactory
nullableFallbackFactory) { super.invocationHandlerFactory(new InvocationHandlerFactory() { @Override public InvocationHandler create(Target target, Map
dispatch) { return new HystrixInvocationHandler(target, dispatch, setterFactory, nullableFallbackFactory); } }); super.contract(new HystrixDelegatingContract(contract)); return super.build();}复制代码

上面这段代码是不是跟Sentinel包装的类似,不同的是Sentinel构造的是SentinelInvocationHandler ,Hystrix构造的是HystrixInvocationHandle。在HystrixInvocationHandler的invoke方法中进行HystrixCommand的包装。

欢迎加入我的知识星球,一起交流技术,免费学习猿天地的课程(

PS:目前星球中正在星主的带领下组队学习Sentinel,等你哦!

转载地址:http://ujsao.baihongyu.com/

你可能感兴趣的文章
1.4 注册系统的逻辑与结构
查看>>
NOIP模拟2017.6.11解题报告
查看>>
Scramble String
查看>>
Linux基础:CentOS安装python3.7
查看>>
Daily Scrum: 2012/11/27
查看>>
vue学习中v-if和v-show一起使用的问题
查看>>
获取一个月前的当前时间
查看>>
第三期 预测——1.简介
查看>>
behavior planning——12.example cost funtion -lane change penalty
查看>>
基于 Spring + Atomikos + Mybatis的多数据源配置demo
查看>>
随笔-刚毕业找工作的点滴(程序员)
查看>>
利用poi3.8中SXSSFWorkbook实现大数据量导出excel
查看>>
day34-1 面向对象概述
查看>>
GCD之dispatch queue
查看>>
【Oracle】-初识PL/SQL
查看>>
黄聪:超实用的PHPExcel[导入][导出]实现方法总结
查看>>
模板变量,过滤器和静态文件引入
查看>>
Oracle 中的 Schema
查看>>
Web APi之认证(Authentication)两种实现方式后续【三】(十五)
查看>>
一条语句简单解决“每个Y的最新X”的SQL经典问题
查看>>