Sentinel初始化之InitFunc实现类加载

  这里简单记录一下Sentinel在接收第一次请求来临是做的初始化准备工作.此工作是利用JDK的ServiceLoader(A simple service-provider loading facility)加载实现的.Sentinel的所有准备工作都是从加载InitFunc开始,然后InitFunc的实现类又使用ServiceLoader去加载其它需要加载资源.
第一次请求来临时,也就是调用entry();方法的时候

  /**
    * Checking all {@link Rule}s about the resource.
    *
    * @param name the unique name of the protected resource
    * @throws BlockException if the block criteria is met, eg. when any rule's threshold is exceeded.
    */
   public static Entry entry(String name) throws BlockException {
       return Env.sph.entry(name, EntryType.OUT, 1, OBJECTS0);
   }

进入这个方法的时候就Env.class中的静态代码块开始了初始化工作.

public class Env {
  public static final NodeBuilder nodeBuilder = new DefaultNodeBuilder();
  public static final Sph sph = new CtSph();
  static {
      // 如果初始化失败,进程将会退出
      InitExecutor.doInit();
  }
}

进入InitExecutor阅读:

/**
* 加载已经注册的功能模块,并按照注册的顺序执行
*/
public final class InitExecutor {
  private static AtomicBoolean initialized = new AtomicBoolean(false);
  /**
   *如果在加载某一个{@link InitFunc}出现异常,初始化进程将立即中断,应用将退出.
   * 初始化动作只执行一次.
   */
  public static void doInit() {
  	//判断是否是第一次初始化,不是则直接返回
      if (!initialized.compareAndSet(false, true)) {
          return;
      }
      try {
      //此处去加载"META-INF/services/"目录下所配置的所有实现了InitFunc接口的类
          ServiceLoader<InitFunc> loader = ServiceLoader.load(InitFunc.class);
          List<OrderWrapper> initList = new ArrayList<OrderWrapper>();
          for (InitFunc initFunc : loader) {
              RecordLog.info("[InitExecutor] Found init func: " + initFunc.getClass().getCanonicalName());
              //将加载完的所有实现类排序
              insertSorted(initList, initFunc);
          }
          for (OrderWrapper w : initList) {
          //挨个执行每个InitFunc实现类的init()方法,init()方法又会去加载其它所需资源
              w.func.init();
              RecordLog.info(String.format("[InitExecutor] Initialized: %s with order %d",
                  w.func.getClass().getCanonicalName(), w.order));
          }
      } catch (Exception ex) {
          RecordLog.warn("[InitExecutor] Init failed", ex);
          ex.printStackTrace();
      } catch (Error error) {
          RecordLog.warn("[InitExecutor] Init failed with fatal error", error);
          error.printStackTrace();
          throw error;
      }
  }
  private static void insertSorted(List<OrderWrapper> list, InitFunc func) {
  //获取func的执行顺序
      int order = resolveOrder(func);
      int idx = 0;
      for (; idx < list.size(); idx++) {
          if (list.get(idx).getOrder() > order) {
              break;
          }
      }
      //按照执行顺序的先后加到list中
      list.add(idx, new OrderWrapper(order, func));
  }
  private static int resolveOrder(InitFunc func) {
  //获取实现类的执行顺序,如果没有指定InitOrder则是最大执行顺序Integer.MAX_VALUE
      if (!func.getClass().isAnnotationPresent(InitOrder.class)) {
          return InitOrder.LOWEST_PRECEDENCE;
      } else {
          return func.getClass().getAnnotation(InitOrder.class).value();
      }
  }
  private InitExecutor() {}
  //将InitFunc 实现类和自己的执行顺序包装在OrderWrapper 中
  private static class OrderWrapper {
      private final int order;
      private final InitFunc func;
      OrderWrapper(int order, InitFunc func) {
          this.order = order;
          this.func = func;
      }
      int getOrder() {
          return order;
      }
      InitFunc getFunc() {
          return func;
      }
  }
}

InitFunc.class

public interface InitFunc {
    void init() throws Exception;
}

InitFunc的实现类大约有如下几个(其中也包括一些测试用例中的):

  1. CommandCenterInitFunc:用与初始化所有CommandCenter;
  2. DefaultClusterClientInitFunc:用与初始化集群限流客户端的所需资源;
  3. DefaultClusterServerInitFunc:用与初始化集群限流服务端的所需资源;
  4. FileDataSourceInit:用于初始化文件数据源,在实际生产中我们可以用MySQL或Nacos等作为数据源;
  5. HeartbeatSenderInitFunc:用于初始化心跳发送者,此处有两个选择HttpHeartbeatSender,SimpleHttpHeartbeatSender;
  6. ParamFlowStatisticSlotCallbackInit:用于初始化参数流控回调.

此处InitFunc就加载完了,至于init()方法去加载其它的资源我将会在其它文章中分享.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值