Spring Cloud Alibaba Sentinel Entry的创建流程

该博客详细介绍了Spring Boot应用中整合Sentinel的配置过程,包括初始化配置、Sentinel自动配置类的逻辑、Sentinel切面的使用以及资源的创建。SentinelAutoConfiguration类初始化时,设置了系统属性并读取配置文件中的相关参数。SentinelResourceAspect作为切面,通过@SentinelResource注解对方法进行增强,实现流量控制、熔断等。整个流程涉及到了Sentinel的动态数据源、日志配置、系统参数设置等多个方面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、注册

首先执行SentinelAutoConfiguration的init方法。

@PostConstruct
private void init() {
    //设置系统属性 csp.sentinel.log.dir
   if (StringUtils.isEmpty(System.getProperty(LogBase.LOG_DIR))
         && StringUtils.hasText(properties.getLog().getDir())) {
      System.setProperty(LogBase.LOG_DIR, properties.getLog().getDir());
   }
    //csp.sentinel.log.use.pid
   if (StringUtils.isEmpty(System.getProperty(LogBase.LOG_NAME_USE_PID))
         && properties.getLog().isSwitchPid()) {
      System.setProperty(LogBase.LOG_NAME_USE_PID,
            String.valueOf(properties.getLog().isSwitchPid()));
   }
    //csp.sentinel.app.name
   if (StringUtils.isEmpty(System.getProperty(SentinelConfig.APP_NAME_PROP_KEY))
         && StringUtils.hasText(projectName)) {
      System.setProperty(SentinelConfig.APP_NAME_PROP_KEY, projectName);
   }
    //csp.sentinel.api.port
   if (StringUtils.isEmpty(System.getProperty(TransportConfig.SERVER_PORT))
         && StringUtils.hasText(properties.getTransport().getPort())) {
      System.setProperty(TransportConfig.SERVER_PORT,
            properties.getTransport().getPort());
   }
    //csp.sentinel.dashboard.server
   if (StringUtils.isEmpty(System.getProperty(TransportConfig.CONSOLE_SERVER))
         && StringUtils.hasText(properties.getTransport().getDashboard())) {
      System.setProperty(TransportConfig.CONSOLE_SERVER,
            properties.getTransport().getDashboard());
   }
    //csp.sentinel.heartbeat.interval.ms
   if (StringUtils.isEmpty(System.getProperty(TransportConfig.HEARTBEAT_INTERVAL_MS))
         && StringUtils
               .hasText(properties.getTransport().getHeartbeatIntervalMs())) {
      System.setProperty(TransportConfig.HEARTBEAT_INTERVAL_MS,
            properties.getTransport().getHeartbeatIntervalMs());
   }
    //csp.sentinel.heartbeat.client.ip
   if (StringUtils.isEmpty(System.getProperty(TransportConfig.HEARTBEAT_CLIENT_IP))
         && StringUtils.hasText(properties.getTransport().getClientIp())) {
      System.setProperty(TransportConfig.HEARTBEAT_CLIENT_IP,
            properties.getTransport().getClientIp());
   }
    //csp.sentinel.charset
   if (StringUtils.isEmpty(System.getProperty(SentinelConfig.CHARSET))
         && StringUtils.hasText(properties.getMetric().getCharset())) {
      System.setProperty(SentinelConfig.CHARSET,
            properties.getMetric().getCharset());
   }
    //csp.sentinel.metric.file.single.size
   if (StringUtils
         .isEmpty(System.getProperty(SentinelConfig.SINGLE_METRIC_FILE_SIZE))
         && StringUtils.hasText(properties.getMetric().getFileSingleSize())) {
      System.setProperty(SentinelConfig.SINGLE_METRIC_FILE_SIZE,
            properties.getMetric().getFileSingleSize());
   }
    //csp.sentinel.metric.file.total.count
   if (StringUtils
         .isEmpty(System.getProperty(SentinelConfig.TOTAL_METRIC_FILE_COUNT))
         && StringUtils.hasText(properties.getMetric().getFileTotalCount())) {
      System.setProperty(SentinelConfig.TOTAL_METRIC_FILE_COUNT,
            properties.getMetric().getFileTotalCount());
   }
    //csp.sentinel.flow.cold.factor
   if (StringUtils.isEmpty(System.getProperty(SentinelConfig.COLD_FACTOR))
         && StringUtils.hasText(properties.getFlow().getColdFactor())) {
      System.setProperty(SentinelConfig.COLD_FACTOR,
            properties.getFlow().getColdFactor());
   }
    //csp.sentinel.web.servlet.block.page
   if (StringUtils.hasText(properties.getBlockPage())) {
      setConfig(BLOCK_PAGE_URL_CONF_KEY, properties.getBlockPage());
   }

   // earlier initialize	是否需要提前初始化 这个放后面。
   if (properties.isEager()) {
      InitExecutor.doInit();
   }

}

然后是SentinelAutoConfiguration的sentinelBeanPostProcessor

@Bean
@ConditionalOnMissingBean
@ConditionalOnClass(name = "org.springframework.web.client.RestTemplate")
@ConditionalOnProperty(name = "resttemplate.sentinel.enabled", havingValue = "true",
      matchIfMissing = true)
public SentinelBeanPostProcessor sentinelBeanPostProcessor(
      ApplicationContext applicationContext) {
   return new SentinelBeanPostProcessor(applicationContext);
}

这个bean只是 简单的将applicationContext赋值给成员变量。

SentinelWebFluxAutoConfiguration的构造方法。

因为这里是集成了gatway。

//三个成员变量
//private final List<ViewResolver> viewResolvers;
//private final ServerCodecConfigurer serverCodecConfigurer;
//@Autowired
//private Optional<BlockRequestHandler> blockRequestHandler;
public SentinelWebFluxAutoConfiguration(
      ObjectProvider<List<ViewResolver>> viewResolvers,
      ServerCodecConfigurer serverCodecConfigurer) {
   this.viewResolvers = viewResolvers.getIfAvailable(Collections::emptyList);
   this.serverCodecConfigurer = serverCodecConfigurer;
}
@PostConstruct
public void init() {
   blockRequestHandler.ifPresent(WebFluxCallbackManager::setBlockHandler);
}

SentinelAutoConfiguration.SentinelConverterConfiguration

@ConditionalOnClass(ObjectMapper.class)
@Configuration(proxyBeanMethods = false)
protected static class SentinelConverterConfiguration {

   @Configuration(proxyBeanMethods = false)
   protected static class SentinelJsonConfiguration {

      private ObjectMapper objectMapper = new ObjectMapper();

      public SentinelJsonConfiguration() {
         objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
               false);
      }

      @Bean("sentinel-json-flow-converter")
      public JsonConverter jsonFlowConverter() {
         return new JsonConverter(objectMapper, FlowRule.class);
      }

      @Bean("sentinel-json-degrade-converter")
      public JsonConverter jsonDegradeConverter() {
         return new JsonConverter(objectMapper, DegradeRule.class);
      }

      @Bean("sentinel-json-system-converter")
      public JsonConverter jsonSystemConverter() {
         return new JsonConverter(objectMapper, SystemRule.class);
      }

      @Bean("sentinel-json-authority-converter")
      public JsonConverter jsonAuthorityConverter() {
         return new JsonConverter(objectMapper, AuthorityRule.class);
      }

      @Bean("sentinel-json-param-flow-converter")
      public JsonConverter jsonParamFlowConverter() {
         return new JsonConverter(objectMapper, ParamFlowRule.class);
      }

   }

SentinelAutoConfiguration

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

这里注册了一个切面类,用来对标注@SentinelResource 注解的方法进行增强。

@Bean
@ConditionalOnMissingBean
public SentinelDataSourceHandler sentinelDataSourceHandler(
      DefaultListableBeanFactory beanFactory, SentinelProperties sentinelProperties,
      Environment env) {
   return new SentinelDataSourceHandler(beanFactory, sentinelProperties, env);
}

这里是读取配置中心配置的Sentinel的配置。

2、Sentinel的切面

注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface SentinelResource {
    String value() default "";
    //IN 和 OUT  输入绑定和输出绑定
    EntryType entryType() default EntryType.OUT;
    int resourceType() default 0;
    String blockHandler() default "";
    Class<?>[] blockHandlerClass() default {};
    String fallback() default "";
    String defaultFallback() default "";
    Class<?>[] fallbackClass() default {};
    Class<? extends Throwable>[] exceptionsToTrace() default {Throwable.class};
    Class<? extends Throwable>[] exceptionsToIgnore() default {};
}

切面类

@Aspect
public class SentinelResourceAspect extends AbstractSentinelAspectSupport {

    @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);
        if (annotation == null) {
            // Should not go through here.
            throw new IllegalStateException("Wrong state for SentinelResource annotation");
        }
        //获取资源名称,如果注解资源名称为空,则资源名称为 className:methodName(参数类型名称以逗号分割)
        String resourceName = getResourceName(annotation.value(), originMethod);
        //获取entryType
        EntryType entryType = annotation.entryType();
        //获取resourceType
        int resourceType = annotation.resourceType();
        Entry entry = null;
        try {
            //生成一个Entry
            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();
            // The ignore list will be checked first.
            if (exceptionsToIgnore.length > 0 && exceptionBelongsTo(ex, exceptionsToIgnore)) {
                throw ex;
            }
            //抛出的异常是注解中 exceptionsToTrace 规定的异常,执行fullback方法
            if (exceptionBelongsTo(ex, annotation.exceptionsToTrace())) {
                traceException(ex);
                return handleFallback(pjp, annotation, ex);
            }

            // No fallback function can handle the exception, so throw it out.
            throw ex;
        } finally {
            //方法执行完,entry退出
            if (entry != null) {
                entry.exit(1, pjp.getArgs());
            }
        }
    }
}

环绕通知,请求的出入会进行相应的一些操作。

创建entry

//com.alibaba.csp.sentinel.SphU#entry
public static Entry entry(String name, int resourceType, EntryType trafficType, Object[] args)
    throws BlockException {
    return Env.sph.entryWithType(name, resourceType, trafficType, 1, args);
}

Env类

public class Env {

    public static final Sph sph = new CtSph();

    static {
        //这里会初始化拉取线程,如果eager为false,为true的话会在自动配置类里面初始化
        // If init fails, the process will exit.
        InitExecutor.doInit();
    }

}

根据类型创建entry

//com.alibaba.csp.sentinel.CtSph#entryWithType
public Entry entryWithType(String name, int resourceType, EntryType entryType, int count, Object[] args)
    throws BlockException {
    return entryWithType(name, resourceType, entryType, count, false, args);
}
//com.alibaba.csp.sentinel.CtSph
public Entry entryWithType(String name, int resourceType, EntryType entryType, int count, boolean prioritized,
                           Object[] args) throws BlockException {
    //生成一个resouceWrapper	对资源的一个包装
    StringResourceWrapper resource = new StringResourceWrapper(name, entryType, resourceType);
    return entryWithPriority(resource, count, prioritized, args);
}

entry的具体创建逻辑在下一篇。

### 阿里巴巴 Sentinel 使用教程及相关文档 #### 什么是 SentinelSentinel 是阿里巴巴开源的一款面向分布式服务架构的流量控制、熔断降级组件,能够帮助开发者保障系统的稳定性。它提供了实时监控、限流、降级以及系统保护等功能,适用于微服务治理场景[^2]。 #### 主要特性 1. **流量控制**:支持基于 QPS 和并发线程数两种模式的限流策略。 2. **熔断降级**:当调用链路中的某个环节不可用或者响应时间过长时,会对整个请求进行快速失败处理。 3. **系统负载保护**:根据 CPU 负载或其他自定义指标对入口流量进行控制。 4. **实时监控与告警**:提供丰富的仪表盘展示当前系统的运行状态。 5. **扩展性强**:支持多种框架适配(如 Spring Cloud、Dubbo 等),并允许用户自定义规则和处理器逻辑[^3]。 #### 安装与配置指南 以下是使用 Alibaba Sentinel 的基本流程: ##### 1. 添加 Maven 依赖 在项目的 `pom.xml` 文件中添加以下依赖项: ```xml <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>最新版本号</version> </dependency> ``` ##### 2. 启动 Sentinel 控制台 下载官方提供的 Sentinel Dashboard 并启动服务端程序。可以通过访问 http://localhost:8080 进入管理界面[^1]。 ##### 3. 注解方式实现资源保护 下面是一个简单的例子,展示了如何利用 `@SentinelResource` 注解来定义受保护的业务方法,并指定异常处理函数: ```java import com.alibaba.csp.sentinel.annotation.SentinelResource; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @GetMapping("/hello") @SentinelResource(value = "hello", blockHandler = "handleBlock") public String hello() { return "Hello, world!"; } public String handleBlock(BlockException ex) { return "Blocked by Sentinel: " + ex.getClass().getSimpleName(); } } ``` 上述代码片段表明,在 `/hello` 接口上应用了名为 `"hello"` 的资源限制条件;如果发生阻塞事件,则触发 `handleBlock()` 方法返回定制化的错误消息[^1]。 ##### 4. 自定义规则设置 可以手动编写 Java 代码动态调整限流参数,如下所示: ```java import com.alibaba.csp.sentinel.Entry; import com.alibaba.csp.sentinel.SphU; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; import java.util.ArrayList; import java.util.List; public class FlowControlExample { public static void main(String[] args) throws InterruptedException { initFlowRules(); while (true){ Entry entry = null; try{ entry = SphU.entry("custom_resource"); System.out.println("Passed..."); }catch(Exception e){ System.err.println(e.getMessage()); }finally{ if(entry !=null){ entry.exit(); } } Thread.sleep(10); } } private static void initFlowRules(){ List<FlowRule> rules=new ArrayList<>(); FlowRule rule=new FlowRule(); rule.setResource("custom_resource"); rule.setGrade(com.alibaba.csp.sentinel.slots.block.flow.RuleConstant.FLOW_GRADE_QPS); rule.setCount(2); // 设置每秒最多允许两个请求 rules.add(rule); FlowRuleManager.loadRules(rules); } } ``` 此示例演示了创建一个新的资源名称为 `"custom_resource"` 的限流规则,并将其阈值设定为每秒钟只接受两次请求[^4]。 #### 参考链接 更多详细资料可查阅官方文档页面:https://github.com/alibaba/Sentinel/wiki 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值