基于SpringCloud手写一个简易版Sentinel
目录
- Sentinel 是什么?
- 定义注解
- 定义切面处理器
- 测试降级
Sentinel 是什么? 随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
不可否认的是,Sentinel功能丰富,并且在提供好用的dashboard提供配置,但是Sentinel在集成到项目中时需要引入多个依赖,并且需要阅读相关文档,以及dashboard中的相关配置才可以接入到项目中,这个过程还是较为复杂的。
如果我们的项目并不需要这么多的功能,只是需要当某个方法或者某个功能发生异常的时候可以实现降级,并不是直接中断程序,该业务功能不是主流程,那么我们为了实现这样一个小功能的时候,将Sentinel集成到项目中的过程显然是较为复杂的,那么这个时候,就需要我们实现一个简答的功能降级的通用方式,下面就一起看看一个简易版的Sentinel的实现
当然,实现这个功能,只需要一个try-catch就可以搞定个,但是我们需要的是try-catch吗?No! 我们需要的是优雅~ 我想你也不想看到满屏的try-catch吧,如果哪天这个方法无需降级的时候,再去一行一行删代码吗?
示例代码已收录到Github: github.com/chenliang15…
定义注解
第一步,定义一个通用注解,这个注解可以帮助我们无侵入性的实现功能降级,并且提供丰富的属性,让注解的通用性和灵活性更强
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@Documented@Inheritedpublic @interface DegradeResource {// 降级的方法名称String fallback(); // 降级的类名称,可选Class>[] fallbackClass() default {}; // 指定降级异常,可选Class extends Throwable>[] exceptionHandle() default {}; }
- fallback:降价方法的名称,需要指定降级方法的名称,才可以在发生异常时调用降级方法,必选参数。
必须为public
方法返回类型、方法参数必须和原始方法保持一致,最后一个参数允许多一个Throwable,用来接收发生的异常
- fallbackClass:指定降级方法所在的class,可选参数,如果不指定则默认降级方法在当前class中
- exceptionHandle:指定异常处理,当发生指定的异常时才选择进行降级,可选参数,数组类型,可以接收多个异常类型
定义切面处理器
当资源降级注解定义之后,我们就需要一个切面处理器,对定义的降级注解做切面处理,当调用的方法上有@DegradeResource注解时,会通过切面处理器进行处理
@Aspectpublic class DegradeResourceAspect {@Around("@annotation(degradeResource)")public Object doAround(ProceedingJoinPoint pjp, DegradeResource degradeResource) throws Throwable {try {return pjp.proceed(); } catch(Throwable e){// need to trace exception listClass extends Throwable>[] exceptions = degradeResource.exceptionHandle(); if(exceptions.length > 0) {List> exceptionList = Arrays.asList(exceptions); // 判断是否为同一个个异常if (exceptionBelongTo(e, exceptionList)) {return handleFallbackMethod(pjp, degradeResource, e); } else {throw e; }}return handleFallbackMethod(pjp, degradeResource, e); }}/*** if the throw exception is belong to exception trace list** @param e* @param exceptionList* @return*/private boolean exceptionBelongTo(Throwable e, List > exceptionList) {for (Class extends Throwable> aClass : exceptionList) {if(aClass.isAssignableFrom(e.getClass())) {return true; }}return false; }/*** invoke fallback method**/private Object handleFallbackMethod(ProceedingJoinPoint pjp, DegradeResource degradeResource, Throwable e) throws Throwable {// fallback methodString fallback = degradeResource.fallback(); if(StringUtils.isEmpty(fallback)) {throw e; }// fallback classClass> clazz = degradeResource.fallbackClass().length > 0 ? degradeResource.fallbackClass()[0] : pjp.getTarget().getClass(); // 获取当前执行的方法名称Method fallbackMethod = findFallbackMethod(pjp, clazz, fallback); if(Objects.isNull(fallbackMethod)) {throw e; }// fallback method argsObject[] args; Object[] originArgs = pjp.getArgs(); int paramCount = fallbackMethod.getParameterTypes().length; if(originArgs.length == paramCount) {args = originArgs; } else {// fill throwable to fallback method argsargs = Arrays.copyOf(originArgs, originArgs.length + 1); args[args.length - 1] = e; }// if staticif(Modifier.isStatic(fallbackMethod.getModifiers())) {return fallbackMethod.invoke(null, args); }return fallbackMethod.invoke(clazz.newInstance(), args); }private Method findFallbackMethod(ProceedingJoinPoint pjp, Class> clazz, String fallbackName) {MethodSignature signers = (MethodSignature) pjp.getSignature(); Class>[] originParams = signers.getParameterTypes(); Class>[] paramsWithException = Arrays.copyOf(originParams, originParams.length + 1); paramsWithException[paramsWithException.length - 1] = Throwable.class; // find fallback method with origin paramsMethod method = findMethod(clazz, originParams, fallbackName, signers.getReturnType()); if(method == null) {// find fallback method with exception paramsmethod = findMethod(clazz, paramsWithException, fallbackName, signers.getReturnType()); }return method; }private Method findMethod(Class> clazz, Class>[] paramsType, String fallbackName, Class> returnType) {Method[] declaredMethods = clazz.getDeclaredMethods(); for (Method method : declaredMethods) {if(method.getName().equals(fallbackName)&& returnType.isAssignableFrom(method.getReturnType())&& Arrays.equals(paramsType, method.getParameterTypes())) {return method; }}return null; }}
总体的流程为:当扫描到切面时,第一步先正常执行方法,当方法发生异常时,判断当前是否制定异常,如果没有指定异常处理类型,那么就默认走降级方法,如果当前指定了降级的异常处理类型,那么就判断当前方法抛出的异常是否为需要处理的异常,如果是则调用降级方法,如果不是需要处理的异常,那么就抛出异常。
符合当前场景的需要,简单化的异常降级
测试降级
总共测试了3中方式的异常降级,分别为默认所有异常降级、指定异常降级、指定降级方法的处理类
@Servicepublic class DegradeResourceTestService {@DegradeResource(fallback = "findByIdFromCacheFallback1")public String findById(String id) {int i = Integer.parseInt(id); System.out.println("id=" + id); return "ok = " + id; }@DegradeResource(fallback = "findByIdFromCacheFallback2", exceptionHandle = {NumberFormatException.class})public String findByIdWithException(String id) {int i = Integer.parseInt(id); System.out.println("id=" + id); return "ok = " + id; }/*** 支持指定fallback method的class,将降级方法统一放置指定的class中**/@DegradeResource(fallback = "findByIdFromCacheFallback3", exceptionHandle = {NumberFormatException.class},fallbackClass = {FallbackClassService.class})public String findByIdWithFallbackClass(String id) {int i = Integer.parseInt(id); System.out.println("id=" + id); return "ok = " + id; }/*** fallback method可以只接受原始函数的参数*/public String findByIdFromCacheFallback1(String id) {return "fallback1 = " + id; }/*** fallback method 不仅可以接收原始方法的参数,还可以接收具体的Exception**/public String findByIdFromCacheFallback2(String id, Throwable e) {System.out.println("fallback method exception:" + e); return "fallback2 = " + id; }}
结果:
文章图片
可以看到,当发生异常时,可以通过降级保证主流程的通常,对于非主流程的功能,我们可以通过@DegradeResource注解保证流程的完善和降级方案,保证用户的体验和程序的正常。
【基于SpringCloud手写一个简易版Sentinel】以上就是基于SpringCloud手写一个简易版Sentinel的详细内容,更多关于SpringCloud手写Sentinel的资料请关注脚本之家其它相关文章!
推荐阅读
- 基于微信小程序带后端ssm接口小区物业管理平台设计
- 基于|基于 antd 风格的 element-table + pagination 的二次封装
- 基于爱,才会有“愿望”当“要求”。2017.8.12
- javaweb|基于Servlet+jsp+mysql开发javaWeb学生成绩管理系统
- JavaScript|vue 基于axios封装request接口请求——request.js文件
- 韵达基于云原生的业务中台建设 | 实战派
- EasyOA|EasyOA 基于SSM的实现 未完成总结与自我批判
- 基于stm32智能风扇|基于stm32智能风扇_一款基于STM32的智能灭火机器人设计
- stm32|基于STM32和freeRTOS智能门锁设计方案
- Python|Python 基于datetime库的日期时间数据处理