Nacos系列文章目前已出:
- Nacos高可用集群搭建
- Nacos配置中心使用:应用间配置共享、扩展配置文件加载优先级、新老版本差异
- Nacos优先使用本地Nacos配置文件验证,源头LocalConfigInfoProcessor.getFailover()
- 图文详述Nacos服务发现源码分析
- 图文详述Nacos服务注册源码分析
- Spring ApplicationContext的事件机制是什么?在Nacos中如何应用?
- 图文源码分析Nacos如何实时感知服务提供者实例信息/个数的变更?
博主今天复习Nacos源码的时候,发现了一个算是有意思的细节点,这里分享一下。
当nacos客户端运⾏起来之后,它只是去做服务注册、配置获取等操作;并不会立即去请求服务信息;当第一次请求时候,才会去获取服务,即懒加载机制
;
Client端做服务发现时,无论是否能从本地缓存中获取到服务实例信息,都会启动一个定时任务(每秒做一次服务实例信息的更新)。然而由于可能多个请求同时要做服务发现,这样总不能每一次做服务发现时都去启动一个定时任务做服务实例信息更新吧。所以肯定要有一个机制去确保针对某一个Cluster下的Service,当前Client只会启动一个定时任务。
HostReactor#scheduleUpdateIfAbsent()方法负责启动做服务实例信息更新的定时任务。
从方法名也能看出来:是当定时任务不存在时,才会启动一个定时任务。
private final Map> futureMap = new HashMap>();public void scheduleUpdateIfAbsent(String serviceName, String clusters) {if (futureMap.get(ServiceInfo.getKey(serviceName, clusters)) != null) {return;}synchronized (futureMap) {if (futureMap.get(ServiceInfo.getKey(serviceName, clusters)) != null) {return;}ScheduledFuture> future = addTask(new UpdateTask(serviceName, clusters));futureMap.put(ServiceInfo.getKey(serviceName, clusters), future);}
}
看一下这个代码逻辑:
既然是DCL的变种版,为了futureMap没有被volatile关键字修饰,不会有指令重排序的问题吗?
Double check Lock确保类单例的代码如下:
public class DoubleCheckLazySingleton {private volatile static DoubleCheckLazySingleton singleton;private DoubleCheckLazySingleton() {}public DoubleCheckLazySingleton getSingleton() {if (singleton == null) {synchronized (this) {//只有在singleton为null的时候才创建实例if (singleton == null) {singleton = new DoubleCheckLazySingleton();}}}return singleton;}
}