断路器:https://martinfowler.com/bliki/CircutiBreaker.html
核心思想:
在断路器对象中封装受保护的方法调用。
该断路器监控调用和断路情况
调用失败触发阈值后,后续调用直接由短路器返回错误,不再执行实际调用。
理解:
客户端通过circuit breaker调用服务提供者,正常的时候可以调用。如果服务提供方出现了问题,发生了超时, 前几次可以超时处理, 到达一个阀值可以通过断路器进行处理, 就不再向服务方发起请求。
import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; @Aspect @Component @Slf4j public class CircuitBreakerAspect { // 阀值 private static final Integer THRESHOLD = 3; //记录失败的次数 private Map<String, AtomicInteger> counter = new ConcurrentHashMap<>(); // 记录被保护的次数 private Map<String, AtomicInteger> breakCounter = new ConcurrentHashMap<>(); /** * * @param pjp 程序连接点 * @return * @throws Throwable */ @Around("execution(* 拦截的区域") public Object doWithCircuitBreaker(ProceedingJoinPoint pjp) throws Throwable { // 获取当前执行的方法 String signature = pjp.getSignature().toLongString(); log.info("Invoke {}", signature); Object retVal; try { if (counter.containsKey(signature)) { // 失败次数达到预制,如果保护次数没到,返回null if (counter.get(signature).get() > THRESHOLD && breakCounter.get(signature).get() < THRESHOLD) { log.warn("Circuit breaker return null, break {} times.", breakCounter.get(signature).incrementAndGet()); return null; } } else { counter.put(signature, new AtomicInteger(0)); breakCounter.put(signature, new AtomicInteger(0)); } retVal = pjp.proceed(); counter.get(signature).set(0); breakCounter.get(signature).set(0); } catch (Throwable t) { log.warn("Circuit breaker counter: {}, Throwable {}", counter.get(signature).incrementAndGet(), t.getMessage()); breakCounter.get(signature).set(0); throw t; } return retVal; } }