NacosNamingService在Spring容器中的加载流程

        NacosServiceManage作为Nacos服务的管理器,内部实现了NacosNamingService的实例化。先看一下SpringBoot自动加载NacosServiceManager的流程。

        查看spring-cloud-starter-alibaba-nacos-discovery-2.2.x.RELEASE.jar包下的META-INFO目录下的spring.factories文件通过该文件找到NacosServiceAutoConfiguration类,该类文件内容如下:

@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
@ConditionalOnNacosDiscoveryEnabled
public class NacosServiceAutoConfiguration {

	@Bean
	public NacosServiceManager nacosServiceManager() {
		return new NacosServiceManager();
	}

}

      可以看到,NacosServiceManager类的实例化交由Spring容器进行管理。 那么它与NacosNamingService的实例化有什么关系呢?再通过上述spring.factories文件,找到NacosDiscoveryEndpointAutoConfiguration类,该类文件内容如下:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Endpoint.class)
@ConditionalOnNacosDiscoveryEnabled
public class NacosDiscoveryEndpointAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean
	@ConditionalOnAvailableEndpoint
	public NacosDiscoveryEndpoint nacosDiscoveryEndpoint(
			NacosServiceManager nacosServiceManager,
			NacosDiscoveryProperties nacosDiscoveryProperties) {
		return new NacosDiscoveryEndpoint(nacosServiceManager, nacosDiscoveryProperties);
	}

	@Bean
	@ConditionalOnEnabledHealthIndicator("nacos-discovery")
	public HealthIndicator nacosDiscoveryHealthIndicator(
			NacosServiceManager nacosServiceManager,
			NacosDiscoveryProperties nacosDiscoveryProperties) {
		Properties nacosProperties = nacosDiscoveryProperties.getNacosProperties();
		return new NacosDiscoveryHealthIndicator(
				nacosServiceManager.getNamingService(nacosProperties));
	}
}

看一下实例化NacosDiscoveryHealthIndicator时,构造方法的入参,nacosServiceManager.getNamingService(nacosProperties)方法。

进入该方法,内容如下(具体的实现细节将用代码注释说明):

import static com.alibaba.nacos.api.NacosFactory.createNamingService;

public class NacosServiceManager {

	private static final Logger log = LoggerFactory.getLogger(NacosServiceManager.class);

	private NacosDiscoveryProperties nacosDiscoveryPropertiesCache;

	private NamingService namingService;

	private NamingMaintainService namingMaintainService;
   
	public NamingService getNamingService(Properties properties) {
        // 判断下成员变量namingService是否没空。
		if (Objects.isNull(this.namingService)) {
            // namingService成员变量为空,调用buildNamingService方法。
			buildNamingService(properties);
		}
		return namingService;
	}

    private NamingService buildNamingService(Properties properties) {
        // 可以看到namingService的实例化采用了单例模式,并使用双重校检机制保证了并发安全
        // 但有问题:namingService成员变量没有用volatile修饰,指令重排会造成对象的半初始化问题,虽然该问题的场景很难出现。
		if (Objects.isNull(namingService)) {
			synchronized (NacosServiceManager.class) {
				if (Objects.isNull(namingService)) {                  
					namingService = createNewNamingService(properties);
				}
			}
		}
		return namingService;
	}

	private NamingService createNewNamingService(Properties properties) {
		try {
            // 注意:调用的是NacosFactory的静态方法(CSDN不支持代码的斜体),看官们看一下类头的import信息,导入了NacosFactory类的createNamingService静态方法(Java1.5支持导入类的静态成员,包括静态方法)。            
			return createNamingService(properties);
		}
		catch (NacosException e) {
			throw new RuntimeException(e);
		}
	}
}

接着看一下NacosFactory类的createNamingService(Properties properties)方法,内容如下:

public class NacosFactory {

     public static NamingService createNamingService(Properties properties) throws NacosException {
        return NamingFactory.createNamingService(properties);
    }
}

看一下NamingFactory类的createNamingService(Properties properties)方法,内容如下: 

public class NamingFactory {
    public static NamingService createNamingService(Properties properties) throws NacosException {
        try {
           // 通过NacosNamingService的完全限定名获取该类的类对象
            Class<?> driverImplClass = Class.forName("com.alibaba.nacos.client.naming.NacosNamingService");
            // 反射获取指定入参的构造函数对象
            Constructor constructor = driverImplClass.getConstructor(Properties.class);
            // 实例化NacosNamingService
            return (NamingService) constructor.newInstance(properties);
        } catch (Throwable e) {
            throw new NacosException(NacosException.CLIENT_INVALID_PARAM, e);
        }
    }
}

       以上就是NacosNamingService的加载流程。通过源码分析我们可以看到源码使用了哪些设计模式:

(1)单例模式,NacosServiceManager中的buildNamingService(Properties properties)方法。

(2)静态工厂模式,NacosFactoryNamingFactory

       上述源码也有问题,那就是对象的半初始化问题。不知各位看官们对此有什么高见,烦请给予评论。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值