AutoRefreshDataSource
public AutoRefreshDataSource(Converter<S, T> configParser, final long recommendRefreshMs) { super(configParser); if (recommendRefreshMs <= 0) { throw new IllegalArgumentException("recommendRefreshMs must > 0, but " + recommendRefreshMs + " get"); } this.recommendRefreshMs = recommendRefreshMs; startTimerService(); }AutoRefreshDataSource的构造器一开始会调用父类的构造器进行初始化,如下:
AbstractDataSource
AbstractDataSource的构造器是为了给两个变量设值parser和property,其中property是DynamicSentinelProperty的实例。
我们再回到AutoRefreshDataSource中,AutoRefreshDataSource设值完recommendRefreshMs参数后会调用startTimerService方法来开启一个定时的调度任务。
AutoRefreshDataSource#startTimerService
这个方法里面会开启一个线程,每3000ms调用一次run方法。run方法里会首先会校验一下文件有没有被修改过,如果有的话就调用loadConfig来加载配置,然后调用getProperty方法获取父类设置的property来更新配置。
下来我们依次来讲解一下这几个主要的方法:
isModified方法是一个钩子,调用的是FileRefreshableDataSource的isModified方法:
FileRefreshableDataSource#isModified
isModified每次都会查看file有没有被修改,并记录一下修改的时间。
接着往下是调用loadConfig加载文件:
AbstractDataSource#loadConfig
FileRefreshableDataSource#readSource
public String readSource() throws Exception { if (!file.exists()) { // Will throw FileNotFoundException later. RecordLog.warn(String.format("[FileRefreshableDataSource] File does not exist: %s", file.getAbsolutePath())); } FileInputStream inputStream = null; try { inputStream = new FileInputStream(file); FileChannel channel = inputStream.getChannel(); if (channel.size() > buf.length) { throw new IllegalStateException(file.getAbsolutePath() + " file size=" + channel.size() + ", is bigger than bufSize=" + buf.length + ". Can't read"); } int len = inputStream.read(buf); return new String(buf, 0, len, charset); } finally { if (inputStream != null) { try { inputStream.close(); } catch (Exception ignore) { } } } }loadConfig方法的实现还是很清晰的,首先是调用readSource通过io流读取文件,然后再通过传入的解析器解析文件的内容。
接着会调用DynamicSentinelProperty的updateValue方法,遍历监听器更新配置:
DynamicSentinelProperty#updateValue
当然,还没加载FlowRuleManager的时候肯定是没有监听器的。
讲完了FileRefreshableDataSource的父类的加载,我们再回到FileRefreshableDataSource的构造器中。继续往下走会调用firstLoad方法首次加载配置文件初始化一次。
FileRefreshableDataSource#firstLoad
下面我们再看一下FlowRuleManager是怎么注册的。注册的时候会调用register2Property方法进行注册:
FlowRuleManager#register2Property
public static void register2Property(SentinelProperty<List<FlowRule>> property) { AssertUtil.notNull(property, "property cannot be null"); synchronized (LISTENER) { RecordLog.info("[FlowRuleManager] Registering new property to flow rule manager"); currentProperty.removeListener(LISTENER); property.addListener(LISTENER); currentProperty = property; } }