前言之前我们说了如何实现一个带有拦截器功能的SPI。当时我们实现的核心思想是使用责任链+动态代理。今天我们就来说说如何通过动态代理集成sentinel实现断路限流预知alibabasentinel介绍Sentinel是分布式服务架构的一个流控组件。、系统负载保护、热点保护等维度帮助开发者保障微服务的稳定性。sentinelworkflowsentinelkeywordresource+rulesentinelimplementstemplateroutineentry=null;//确保finally会被执行1K),如果大于几千,请作为参数传入,不要直接作为资源名//EntryType表示流量类型(入站/出站),系统规则只对埋点生效INtypeentry=SphU.entry("自定义资源名称");//受保护的业务逻辑//做一些事情...}catch(BlockExceptionex){//资源访问被阻塞、限制或降级//执行相应的处理操作}catch(Exceptionex){//如果需要配置降级rules,需要通过这种方式记录业务异常Tracer.traceEntry(ex,entry);}finally{//一定要保证exit,保证每个entry都和exit配对if(entry!=null){entry.出口();}}sentinelwikihttps://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E9%A1%B5实现思路总体实现思路:动态代理+sentinel实现例程模板核心代码动态代理部分1.定义动态代理接口publicinterfaceCircuitBreakerProxy{ObjectgetProxy(Objecttarget);ObjectgetProxy(Objecttarget,@NullableClassLoaderclassLoader);}2.定义JDK或cglib具体动态实现以jdk动态代理为例publicclassCircuitBreakerJdkProxyimplementsCircuitBreakerProxy,InvocationHandler{@OverridepublicObjectgetProxy(Objecttarget){this.target=target;返回getProxy(target,Thread.currentThread().getContextClassLoader());}@OverridepublicObjectgetProxy(Objecttarget,ClassLoaderclassLoader){this.target=target;返回Proxy.newProxyInstance(classLoader,target.getClass().getInterfaces(),this);}@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{CircuitBreakerInvocationinvocation=newCircuitBreakerInvocation(target,method,args);尝试{返回新的CircuitBreakerInvoker().proceed(invocation);//用InvocationTargetException封装是java.lang.reflect.UndeclaredThrowableException问题}catch(InvocationTargetExceptione){throwe.getTargetException();}}}3、动态代理工具调用publicclassCircuitBreakerProxyFactoryimplementsProxyFactory{@OverridepublicObjectcreateProxy(Objecttarget){if(target.getClass().isInterface()||Proxy.isProxyClass(target.getClass())){返回新的CircuitBreakerJdkProxy().getProxy(target);}返回新的CircuitBreakerCglibProxy().getProxy(target);}}ps:上面动态代理实现的思路是参考了springaop动态代理的实现。具体参考类如下:=circuitBreakerInvocation.getMethod();if("equals".equals(method.getName())){try{ObjectotherHandler=circuitBreakerInvocation.getArgs().length>0&&circuitBreakerInvocation.getArgs()[0]!=null?Proxy.getInvocationHandler(circuitBreakerInvocation.getArgs()[0]):null;返回等于(otherHandler);}赶上(IllegalArgumentExceptione){返回假;}}elseif("hashCode".equals(method.getName())){returnhashCode();}elseif("toString".equals(method.getName())){returntoString();}对象结果=空;StringcontextName="spi_circuit_breaker:";字符串类名=ClassUtils.getClassName(circuitBreakerInvocation.getTarget());StringresourceName=contextName+className+"."+方法.getName();条目条目=空;试试{ContextUtil.enter(contextName);entry=SphU.entry(resourceName,EntryType.OUT,1,circuitBreakerInvocation.getArgs());结果=circuitBreakerInvocation.proceed();}catch(Throwableex){returndoFallBack(ex,entry,circuitBreakerInvocation);}finally{if(entry!=null){entry.exit(1,circuitBreakerInvocation.getArgs());}ContextUtil.exit();}返回结果;}}ps:细心的朋友会发现这个逻辑是Sentinel原生实现例程逻辑示例Demonstration示例准备1.定义接口实现类,添加熔断注解@CircuitBreakerActivate(spiKey="sqlserver",fallbackFactory=SqlServerDialectFallBackFactory.class)publicclassSqlServerDialectimplementsSqlDialect{@OverridepublicStringdialect(){返回“sqlserver”;}}ps:@CircuitBreakerActivate这是一个自定义的断路器注解,springcloudopenfeign的@FeignClient注解大概会有一个熟悉的就是在注解上配置fallbackFactory或者fallbackBack2,定义接口熔断工厂@Slf4j@ComponentpublicclassSqlServerDialectFallBackFactoryimplementsFallbackFactory
