Spring Cloud Alibaba Sentinel对RestTemplate的支持
Spring Cloud Alibaba Sentinel 支持对 RestTemplate 的服务调用使用 Sentinel 进行保护,在构造 RestTemplate bean的时候需要加上 @SentinelRestTemplate 注解。
需要注意的是目前的版本spring-cloud-starter-alibaba-sentinel.0.2.1.RELEASE在配置RestTemplate的时候有个Bug,需要将配置放在Spring Boot的启动类中,也就是@SpringBootApplication注解所在的类。
如果单独放在@Configuration标记的类中目前是有问题的,当然后续版本中会进行修复,对应的问题描述:https://github.com/spring-cloud-incubator/spring-cloud-alibaba/issues/227
@Bean
@SentinelRestTemplate(fallback = "fallback", fallbackClass = ExceptionUtil.class, blockHandler="handleException",blockHandlerClass=ExceptionUtil.class)
public RestTemplate restTemplate() {
	return new RestTemplate();
}
- blockHandler
 限流后处理的方法
- blockHandlerClass
 限流后处理的类
- fallback
 熔断后处理的方法
- fallbackClass
 熔断后处理的类
异常处理类定义需要注意的是该方法的参数跟返回值跟 org.springframework.http.client.ClientHttpRequestInterceptor#interceptor 方法一致,其中参数多出了一个 BlockException 参数用于获取 Sentinel 捕获的异常。
public class ExceptionUtil {
	public static SentinelClientHttpResponse handleException(HttpRequest request,
			byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
		System.err.println("Oops: " + ex.getClass().getCanonicalName());
		return new SentinelClientHttpResponse("custom block info");
	}
	public static SentinelClientHttpResponse fallback(HttpRequest request,
			byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
		System.err.println("fallback: " + ex.getClass().getCanonicalName());
		return new SentinelClientHttpResponse("custom fallback info");
	}
}
原理剖析
核心代码在org.springframework.cloud.alibaba.sentinel.custom.SentinelBeanPostProcessor中,实现了MergedBeanDefinitionPostProcessor接口,MergedBeanDefinitionPostProcessor接口实现了BeanPostProcessor接口。
核心方法就是重写的postProcessMergedBeanDefinition和postProcessAfterInitialization。
postProcessMergedBeanDefinition
private ConcurrentHashMap<String, SentinelRestTemplate> cache = new ConcurrentHashMap<>();
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,
			Class<?> beanType, String beanName) {
	if (checkSentinelProtect(beanDefinition, beanType)) {
	    SentinelRestTemplate sentinelRestTemplate = ((StandardMethodMetadata) beanDefinition
					.getSource()).getIntrospectedMethod()
							.getAnnotation(SentinelRestTemplate.class);
        // 获取SentinelRestTemplate注解对象存储起来
		cache.put(beanName, sentinelRestTemplate);
	}
}
// 判断bean是否加了SentinelRestTemplate注解并且是RestTemplate
private boolean checkSentinelProtect(RootBeanDefinition beanDefinition,
			Class<?> beanType) {
	return beanType == RestTemplate.class
				&& beanDefinition.getSource() instanceof StandardMethodMetadata
				&& ((StandardMethodMetadata) beanDefinition.getSource())
						.isAnnotated(SentinelRestTemplate.class.getName());
}
postProcessAfterInitialization
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
			throws BeansException {
	if (cache.containsKey(beanName)) {
		// add interceptor for each RestTemplate with @SentinelRestTemplate annotation
		StringBuilder interceptorBeanName = new StringBuilder();
        // 缓存中得到注解对象
		SentinelRestTemplate sentinelRestTemplate = cache.get(beanName);
        // 生成interceptorBeanName SentinelProtectInterceptor名称
		interceptorBeanName
					.append(StringUtils.uncapitalize(
							SentinelProtectInterceptor.class.getSimpleName()))
					.append("_")
					.append(sentinelRestTemplate.blockHandlerClass().getSimpleName())
					.append(sentinelRestTemplate.blockHandler()).append("_")
					.append(sentinelRestTemplate.fallbackClass().getSimpleName())
					.append(sentinelRestTemplate.fallback());
		RestTemplate restTemplate = (RestTemplate) bean;
        // 注册SentinelProtectInterceptor
		registerBean(interceptorBeanName.toString(), sentinelRestTemplate);
        // 获取SentinelProtectInterceptor
		SentinelProtectInterceptor sentinelProtectInterceptor = applicationContext
					.getBean(interceptorBeanName.toString(),
							SentinelProtectInterceptor.class);
        // 给restTemplate添加拦截器
		restTemplate.getInterceptors().add(sentinelProtectInterceptor);
	}
	return bean;
}
// 注册SentinelProtectInterceptor类
private void registerBean(String interceptorBeanName,
			SentinelRestTemplate sentinelRestTemplate) {
	// register SentinelProtectInterceptor bean
	DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext
				.getAutowireCapableBeanFactory();
    BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
				.genericBeanDefinition(SentinelProtectInterceptor.class);
	beanDefinitionBuilder.addConstructorArgValue(sentinelRestTemplate);
	BeanDefinition interceptorBeanDefinition = beanDefinitionBuilder
				.getRawBeanDefinition();
	beanFactory.registerBeanDefinition(interceptorBeanName,
				interceptorBeanDefinition);
}
看到这边大家就明白了,其实就是给restTemplate添加拦截器来处理。跟Ribbon中的@LoadBalanced原理是一样的。
SentinelProtectInterceptor
Sentinel RestTemplate 限流的资源规则提供两种粒度:
- schema://host:port/path:协议、主机、端口和路径
- schema://host:port:协议、主机和端口
这两种粒度从org.springframework.cloud.alibaba.sentinel.custom.SentinelProtectInterceptor.intercept(HttpRequest, byte[], ClientHttpRequestExecution)方法中可以看的出来
URI uri = request.getURI();
String hostResource = uri.getScheme() + "://" + uri.getHost()
			+ (uri.getPort() == -1 ? "" : ":" + uri.getPort());
String hostWithPathResource = hostResource + uri.getPath();
下面就是根据hostResource和hostWithPathResource进行限流
ContextUtil.enter(hostWithPathResource);
if (entryWithPath) {
	hostWithPathEntry = SphU.entry(hostWithPathResource);
}
hostEntry = SphU.entry(hostResource);
// 执行Http调用
response = execution.execute(request, body);
在后面就是释放资源,异常处理等代码,大家自己去了解下。
欢迎加入我的知识星球,一起交流技术,免费学习猿天地的课程(http://cxytiandi.com/course)
PS:目前星球中正在星主的带领下组队学习Sentinel,等你哦!


Spring Cloud Alibaba Sentinel对RestTemplate的支持的更多相关文章
- Spring Cloud Alibaba Sentinel对Feign的支持
		Spring Cloud Alibaba Sentinel 除了对 RestTemplate 做了支持,同样对于 Feign 也做了支持,如果我们要从 Hystrix 切换到 Sentinel 是非常 ... 
- Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵进阶实战
		Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵进阶实战 在阅读本文前,建议先阅读<Spring Cloud Alibaba | Sentinel:分布式系 ... 
- Spring Cloud Alibaba | Sentinel: 分布式系统的流量防卫兵初探
		目录 Spring Cloud Alibaba | Sentinel: 分布式系统的流量防卫兵初探 1. Sentinel 是什么? 2. Sentinel 的特征: 3. Sentinel 的开源生 ... 
- Spring Cloud Alibaba | Sentinel: 服务限流基础篇
		目录 Spring Cloud Alibaba | Sentinel: 服务限流基础篇 1. 简介 2. 定义资源 2.1 主流框架的默认适配 2.2 抛出异常的方式定义资源 2.3 返回布尔值方式定 ... 
- Spring Cloud Alibaba | Sentinel: 服务限流高级篇
		目录 Spring Cloud Alibaba | Sentinel: 服务限流高级篇 1. 熔断降级 1.1 降级策略 2. 热点参数限流 2.1 项目依赖 2.2 热点参数规则 3. 系统自适应限 ... 
- Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵基础实战
		Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵基础实战 Springboot: 2.1.8.RELEASE SpringCloud: Greenwich.SR2 ... 
- Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵动态限流规则
		Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵动态限流规则 前面几篇文章较为详细的介绍了Sentinel的使用姿势,还没看过的小伙伴可以访问以下链接查看: &l ... 
- 0.9.0.RELEASE版本的spring cloud alibaba sentinel实例
		sentinel即哨兵,相比hystrix断路器而言,它的功能更丰富.hystrix仅支持熔断,当服务消费方调用提供方发现异常后,进入熔断:sentinel不仅支持异常熔断,也支持响应超时熔断,另外还 ... 
- 0.9.0.RELEASE版本的spring cloud alibaba sentinel+feign降级处理实例
		既然用到了feign,那么主要是针对服务消费方的降级处理.我们基于0.9.0.RELEASE版本的spring cloud alibaba nacos+feign实例添油加醋,把sentinel功能加 ... 
随机推荐
- python调用C++实例:用C++对numpy执行BFS(广度优先搜索)
			下文的代码可能展示不全,详情请下载文件:用cpp遍历ndarray.rar 问题背景: 现在我有一张二值图test.npy,需要对其闭区域进行孔洞填充,如下图所示: 文件下载链接:用cpp遍历ndar ... 
- NLP中的数据增强
			相关方法合集见:https://github.com/quincyliang/nlp-data-augmentation 较为简单的数据增强的方法见论文:https://arxiv.org/pdf/1 ... 
- dotnetcore实现Aop
			dotnetcore实现Aop Aop大家都不陌生,然而今天给大家不将讲官方的filter,今天给大家分享一个轻量级的Aop解决方案(AspectCore) 什么是AspectCore AspectC ... 
- IT兄弟连 HTML5教程 HTML5的曲折发展过程 浏览器之间的大战
			播放电影和音乐要使用播放器,浏览网页就需要使用浏览器.浏览器虽然只是一个设备,并不是开发语言,但在Web开发中必不可少,因为浏览器要去解析HTML5.CSS3和JavaScript等语言用于显示网页, ... 
- 为何我建议1-3年的Java程序员仔细看看这篇文章
			此文的目的是为了督促自己去不断学习,让自己有更明确的方向去提升自己.以技能树为基础,以面试要点为大纲,我觉得比抓住什么看什么要更有目的,更能坚持下去.世界瞬息万变,我们要时刻准备着.时刻提高着自己,才 ... 
- C++ delete 和 delete []的区别
			转载自https://blog.csdn.net/cbNotes/article/details/38900799 1.我们通常从教科书上看到这样的说明:delete 释放new分配的单个对象指针指向 ... 
- GO 基本语法——变量
			基本语法--变量 一.变量的使用 1.1 什么是变量 变量是为存储特定类型的值而提供给内存位置的名称.在go中声明变量有多种语法. 所以变量的本质就是一小块内存,用于存储数据,在程序运行过程中数值可以 ... 
- 资深程序员:学Python我推荐你用这几款编辑器
			Python使用什么编辑比较好,Python编辑器推荐 各位 Pythoner 好啊!在这个烦躁的时代,相聚就是缘分,很高兴各位 Pythoner 能相聚于此,希望接下来的路,我们一起走下去,使用 P ... 
- Python爬取十四万条书籍信息告诉你哪本网络小说更好看
			前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: TM0831 PS:如有需要Python学习资料的小伙伴可以加点击 ... 
- mybatis关联关系映射
			1.一对多关联关系 2.多对多关联关系 首先先用逆向生成工具生成t_hibernate_order.t_hibernate_order_item t_hibernate_book.t_hibernat ... 
