Spring Cloud Alibaba Sentinel Entry的创建流程

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的具体创建逻辑在下一篇。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值