断路器: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;
    }
}
02-12 20:30