How Spring Cloud Sentinel @SentinelResource Enforces Flow Control and Circuit Breaking

This article explains how Spring Cloud Sentinel’s @SentinelResource annotation works, detailing its AOP interception, the responsibility‑chain slot mechanism, flow‑control and circuit‑breaker processing, and shows the relevant configuration and code examples for integrating Sentinel into a Spring Boot backend.

Ops Development Stories
Ops Development Stories
Ops Development Stories
How Spring Cloud Sentinel @SentinelResource Enforces Flow Control and Circuit Breaking

Spring Cloud Sentinel Dependency and Initialization

After adding the spring-cloud-starter-alibaba-sentinel dependency, Spring Boot loads configuration from spring.factories, including classes such as SentinelWebAutoConfiguration, SentinelWebAutoConfiguration, SentinelWebAutoConfiguration, etc.

Version used in this article: sentinel 1.8.0.

@SentinelResource Working Principle

The simplest way to configure flow‑control rules is using the @SentinelResource annotation, which can define flow‑control and fallback rules directly. Example:

@SentinelResource(value = "ResOrderGet",
                  fallback = "fallback",
                  fallbackClass = SentinelResourceExceptionHandler.class,
                  blockHandler = "blockHandler",
                  blockHandlerClass = SentinelResourceExceptionHandler.class)
@GetMapping("/order/get/{id}")
public CommonResult<StockModel> getStockDetails(@PathVariable Integer id) {
    StockModel stockModel = new StockModel();
    stockModel.setCode("STOCK=>1000");
    stockModel.setId(id);
    return CommonResult.success(stockModel);
}

Spring AOP intercepts the getStockDetails method. The bean definition can be found in SentinelAutoConfiguration:

@Bean
@ConditionalOnMissingBean
public SentinelResourceAspect sentinelResourceAspect() {
    return new SentinelResourceAspect();
}

The SentinelResourceAspect processes the annotation as follows:

@Pointcut("@annotation(com.alibaba.csp.sentinel.annotation.SentinelResource)")
public void sentinelResourceAnnotationPointcut() {}

@Around("sentinelResourceAnnotationPointcut()")
public Object invokeResourceWithSentinel(ProceedingJoinPoint pjp) throws Throwable {
    Method originMethod = resolveMethod(pjp);
    SentinelResource annotation = originMethod.getAnnotation(SentinelResource.class);
    String resourceName = getResourceName(annotation.value(), originMethod);
    EntryType entryType = annotation.entryType();
    int resourceType = annotation.resourceType();
    Entry entry = null;
    try {
        entry = SphU.entry(resourceName, resourceType, entryType, pjp.getArgs());
        Object result = pjp.proceed();
        return result;
    } catch (BlockException ex) {
        return handleBlockException(pjp, annotation, ex);
    } catch (Throwable ex) {
        Class<? extends Throwable>[] exceptionsToIgnore = annotation.exceptionsToIgnore();
        if (exceptionsToIgnore.length > 0 && exceptionBelongsTo(ex, exceptionsToIgnore)) {
            throw ex;
        }
        if (exceptionBelongsTo(ex, annotation.exceptionsToTrace())) {
            traceException(ex);
            return handleFallback(pjp, annotation, ex);
        }
        throw ex;
    }
}

Summary of execution: AOP intercepts the method, SphU.entry applies flow‑control rules, then the business method is invoked. If a flow‑control rule is triggered, a BlockException is handled; otherwise, a fallback method may be called.

Responsibility Chain for Flow Control

The core processing method is SphU.entry, which initializes a responsibility chain and executes slots.

private Entry entryWithPriority(ResourceWrapper resourceWrapper, int count, boolean prioritized, Object... args)
        throws BlockException {
    // Initialize responsibility chain
    ProcessorSlot<Object> chain = lookProcessChain(resourceWrapper);
    Entry e = new CtEntry(resourceWrapper, chain, context);
    try {
        // Execute entry
        chain.entry(context, resourceWrapper, null, count, prioritized, args);
    } catch (BlockException e1) {
        e.exit(count, args);
        // Exception will be handled by SentinelResourceAspect
        throw e1;
    } catch (Throwable e1) {
        RecordLog.info("Sentinel unexpected exception", e1);
    }
    return e;
}

The chain is built by DefaultSlotChainBuilder:

public class DefaultSlotChainBuilder implements SlotChainBuilder {
    @Override
    public ProcessorSlotChain build() {
        ProcessorSlotChain chain = new DefaultProcessorSlotChain();
        // Load all ProcessorSlot implementations via SPI, sorted by Order
        List<ProcessorSlot> sortedSlotList = SpiLoader.loadPrototypeInstanceListSorted(ProcessorSlot.class);
        for (ProcessorSlot slot : sortedSlotList) {
            if (!(slot instanceof AbstractLinkedProcessorSlot)) {
                RecordLog.warn("The ProcessorSlot(" + slot.getClass().getCanonicalName() + ") is not an instance of AbstractLinkedProcessorSlot, can't be added into ProcessorSlotChain");
                continue;
            }
            // Add to chain tail
            chain.addLast((AbstractLinkedProcessorSlot<?>) slot);
        }
        return chain;
    }
}

The default slot order (simplified) is:

NodeSelectorSlot

ClusterBuilderSlot

LogSlot

StatisticSlot

AuthoritySlot

SystemSlot

ParamFlowSlot

FlowSlot

DegradeSlot

sentinel slots 原理
sentinel slots 原理

FlowSlot Flow Control

The FlowSlot entry method checks flow rules and then fires the entry:

@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
                  boolean prioritized, Object... args) throws Throwable {
    // Check flow
    checkFlow(resourceWrapper, context, node, count, prioritized);
    fireEntry(context, resourceWrapper, node, count, prioritized, args);
}

The default controller uses a fast‑fail strategy:

@Override
public boolean canPass(Node node, int acquireCount, boolean prioritized) {
    int curCount = avgUsedTokens(node);
    if (curCount + acquireCount > count) {
        return false;
    }
    return true;
}

private int avgUsedTokens(Node node) {
    if (node == null) {
        return DEFAULT_AVG_USED_TOKENS;
    }
    return grade == RuleConstant.FLOW_GRADE_THREAD ? node.curThreadNum() : (int)(node.passQps());
}

If the rule is not passed, a FlowException is thrown, which is later handled by the aspect.

DegradeSlot Circuit Breaking

The DegradeSlot implements circuit‑breaker logic with three states: OPEN, HALF_OPEN, and CLOSED, based on response‑time metrics.

断路器工作协作原理
断路器工作协作原理

Sentinel Web Interceptor

When the @SentinelResource annotation is not used, Sentinel applies flow control via a web interceptor defined in SentinelWebAutoConfiguration:

@Bean
@ConditionalOnProperty(name = "spring.cloud.sentinel.filter.enabled", matchIfMissing = true)
public SentinelWebInterceptor sentinelWebInterceptor(SentinelWebMvcConfig sentinelWebMvcConfig) {
    return new SentinelWebInterceptor(sentinelWebMvcConfig);
}

The interceptor’s preHandle method also calls SphU.entry to enforce the responsibility chain:

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {
    try {
        String resourceName = getResourceName(request);
        if (StringUtil.isEmpty(resourceName)) {
            return true;
        }
        if (increaseReferece(request, this.baseWebMvcConfig.getRequestRefName(), 1) != 1) {
            return true;
        }
        String origin = parseOrigin(request);
        String contextName = getContextName(request);
        ContextUtil.enter(contextName, origin);
        Entry entry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.IN);
        request.setAttribute(baseWebMvcConfig.getRequestAttributeName(), entry);
        return true;
    } catch (BlockException e) {
        try {
            handleBlockException(request, response, e);
        } finally {
            ContextUtil.exit();
        }
        return false;
    }
}

Reference Documentation

https://github.com/alibaba/Sentinel/wiki

https://martinfowler.com/bliki/CircuitBreaker.html

Sentinel flow control diagram
Sentinel flow control diagram
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

javaaopcircuit breakerSpring Cloud Sentinel
Ops Development Stories
Written by

Ops Development Stories

Maintained by a like‑minded team, covering both operations and development. Topics span Linux ops, DevOps toolchain, Kubernetes containerization, monitoring, log collection, network security, and Python or Go development. Team members: Qiao Ke, wanger, Dong Ge, Su Xin, Hua Zai, Zheng Ge, Teacher Xia.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.