1、Nacos客户端启动

1、启动配置
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <version>${version}</version>
</dependency>

   通过SpringCloud注解 @EnableDiscoveryClient 开启服务注册发现功能。
   地址配置 spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848。

2、NacosDiscoveryAutoConfiguration

  使用spring.factories SPI机制加载,NacosDiscoveryAutoConfiguration创建NacosDiscoveryProperties 统一管理配置和NacosServiceDiscovery 服务发现两个对象。

@Bean
@ConditionalOnMissingBean
public NacosDiscoveryProperties nacosProperties() {
    return new NacosDiscoveryProperties();
}

@Bean
@ConditionalOnMissingBean
public NacosServiceDiscovery nacosServiceDiscovery(
        NacosDiscoveryProperties discoveryProperties,NacosServiceManager nacosServiceManager) {
    return new NacosServiceDiscovery(discoveryProperties, nacosServiceManager);
}

  NacosDiscoveryProperties 统一管理客户端配置项,默认搜索顺序 properties -> 命令行参数 -> 环境参数 -> 默认值。
  调整优先级 (命令行配置) -Dnacos.env.first=PROPERTIES|JVM|ENV
  调整优先级 (环境变量配置) NACOS_ENV_FIRST=PROPERTIES|JVM|ENV。

3、NacosServiceRegistryAutoConfiguration

  NacosServiceRegistryAutoConfiguration 自动配置服务注册相关的功能。
  自动注册配置方式: spring.cloud.service-registry.auto-registration.enabled=true,@EnableDiscoveryClient(autoRegister = true)。

@Bean
public NacosServiceRegistry nacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) {
   return new NacosServiceRegistry(nacosDiscoveryProperties);
}

@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosRegistration nacosRegistration(
      ObjectProvider<List<NacosRegistrationCustomizer>> registrationCustomizers,
      NacosDiscoveryProperties nacosDiscoveryProperties,ApplicationContext context) {
   return new NacosRegistration(registrationCustomizers.getIfAvailable(),nacosDiscoveryProperties, context);
}

@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosAutoServiceRegistration nacosAutoServiceRegistration(
      NacosServiceRegistry registry,
      AutoServiceRegistrationProperties autoServiceRegistrationProperties,
      NacosRegistration registration) {
   return new NacosAutoServiceRegistration(registry,autoServiceRegistrationProperties, registration);
}

  NacosRegistration 创建服务实例的信息,如服务名称、IP 地址、端口号等。
  NacosServiceRegistry 将服务实例的信息注册到 Nacos 服务器。
  NacosAutoServiceRegistration 实现自动注册服务实例到 Nacos 服务器。

4、NacosServiceAutoConfiguration

  NacosServiceAutoConfiguration,创建NacosServiceManager是service核心管理类。

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

  NacosServiceManager类的方法getNamingService ,获取NamingService实现类如果为空则通过反射创建对象。

public NamingService getNamingService(Properties properties) {
   if (Objects.isNull(this.namingService)) {
      buildNamingService(properties);
   }
   return namingService;
}

//使用双重检查,避免重复创建对象
private NamingService buildNamingService(Properties properties) {
    if (Objects.isNull(namingService)) {
        synchronized (NacosServiceManager.class) {
            if (Objects.isNull(namingService)) {
                namingService = createNewNamingService(properties);
            }
        }
    }
    return namingService;
}
5、NacosNamingService

  NacosNamingService 主要功能包括服务实例的注册与注销、服务发现等。

public NacosNamingService(String serverList) throws NacosException {
    Properties properties = new Properties();
    properties.setProperty(PropertyKeyConst.SERVER_ADDR, serverList);
    init(properties);
}
    
public NacosNamingService(Properties properties) throws NacosException {
    init(properties);
}
    
private void init(Properties properties) throws NacosException {
    //创建新的配置文件类
    NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(properties);
    //检查是否正确的URL
    ValidatorUtils.checkInitParam(nacosClientProperties);
    this.namespace = InitUtils.initNamespaceForNaming(nacosClientProperties);
    InitUtils.initSerialization();
    InitUtils.initWebRootContext(nacosClientProperties);
    initLogName(nacosClientProperties);
    this.notifierEventScope = UUID.randomUUID().toString();
    this.changeNotifier = new InstancesChangeNotifier(this.notifierEventScope);
    NotifyCenter.registerToPublisher(InstancesChangeEvent.class, 16384);
    NotifyCenter.registerSubscriber(changeNotifier);
    this.serviceInfoHolder = new ServiceInfoHolder(namespace, this.notifierEventScope, 
                                                   nacosClientProperties);
    //创建客户端连接的委托对象
    this.clientProxy = new NamingClientProxyDelegate(this.namespace, serviceInfoHolder, 
                                                     nacosClientProperties, changeNotifier);
}
	//根据不同的配置委托给不同对象,实现处理解耦
    private NamingClientProxy getExecuteClientProxy(Instance instance) {
        return instance.isEphemeral() ? grpcClientProxy : httpClientProxy;
    }

  spring.cloud.nacos.discovery.ephemeral=true|false 配置是否为临时节点。
  持久化节点使用CP(Raft)协议保障数据一致性,临时节点使用AP (Distro) 协议保障数据一致性。
  NamingClientProxyDelegate 会创建NamingHttpClientProxy和NamingGrpcClientProxy对象。
  持久化节点注册使用HTTP客户端,临时节点注册使用gRPC客户端,默认为临时节点。

6、客户端建立连接

  NamingGrpcClientProxy 创建和管理 gRPC客户端,GrpcClient#start()方法与Nacos服务端建立连接,每隔5秒执行健康检查,如果响应失败会重新连接或切换连接。

 public final void start() throws NacosException {
        //修改客户端连接状态
        boolean success = rpcClientStatus.compareAndSet(RpcClientStatus.INITIALIZED, RpcClientStatus.STARTING);
        if (!success) {
            return;
        }
        clientEventExecutor = new ScheduledThreadPoolExecutor(2, r -> {
            Thread t = new Thread(r);
            t.setName("com.alibaba.nacos.client.remote.worker");
            t.setDaemon(true);
            return t;
        });
        // 处理连接事件的消费者
        clientEventExecutor.submit(() -> {
            while (!clientEventExecutor.isTerminated() && !clientEventExecutor.isShutdown()) {
                ConnectionEvent take;
                try {
                    //阻塞获取连接事件
                    take = eventLinkedBlockingQueue.take();
                    if (take.isConnected()) {
                        //连接成功的事件处理
                        notifyConnected();
                    } else if (take.isDisConnected()) {
                        //连接断开的事件处理
                        notifyDisConnected();
                    }
                } catch (Throwable e) {
                }
            }
        });
        //健康检查或连接重连,默认5秒执行一次
        clientEventExecutor.submit(() -> {
            while (true) {
                try {
                    if (isShutdown()) {
                        break;
                    }
                    //获取重新连接任务为空则执行健康检查
                    ReconnectContext reconnectContext = reconnectionSignal
                            .poll(rpcClientConfig.connectionKeepAlive(), TimeUnit.MILLISECONDS);
                    if (reconnectContext == null) {
                        //活动间隔时间是否超过默认值5秒,超过则执行健康检查
                        if (System.currentTimeMillis() - lastActiveTimeStamp >= rpcClientConfig.connectionKeepAlive()) {
                            //健康检查返回成功则更新活动时间,失败则判断是否需要重新连接
                            boolean isHealthy = healthCheck();
                            if (!isHealthy) {
                                if (currentConnection == null) {
                                    continue;
                                }
                                LoggerUtils.printIfInfoEnabled(LOGGER,
                                "[{}] Server healthy check fail, currentConnection = {}",
                                rpcClientConfig.name(), currentConnection.getConnectionId());
                                //连接已关闭则推出
                                RpcClientStatus rpcClientStatus = RpcClient.this.rpcClientStatus.get();
                                if (RpcClientStatus.SHUTDOWN.equals(rpcClientStatus)) {
                                    break;
                                }
                                //设置当前连接为不健康状态
                                boolean statusFLowSuccess = RpcClient.this.rpcClientStatus
                                        .compareAndSet(rpcClientStatus, RpcClientStatus.UNHEALTHY);
                                if (statusFLowSuccess) {
                                    //设置空的连接对象,重新选择server重连
                                    reconnectContext = new ReconnectContext(null, false);
                                } else {
                                    continue;
                                }
                            } else {
                                //更新活动时间
                                lastActiveTimeStamp = System.currentTimeMillis();
                                continue;
                            }
                        } else {
                            continue;
                        }
                    }
                     //判断是否按照指定重新连接,为空会选新取server重连
                    if (reconnectContext.serverInfo != null) {
                        // clear recommend server if server is not in server list.
                        boolean serverExist = false;
                        for (String server : getServerListFactory().getServerList()) {
                            ServerInfo serverInfo = resolveServerInfo(server);
                            if (serverInfo.getServerIp().equals(reconnectContext.serverInfo.getServerIp())){
                                serverExist = true;
                                reconnectContext.serverInfo.serverPort = serverInfo.serverPort;
                                break;
                            }
                        }
                        if (!serverExist) {
                            LoggerUtils.printIfInfoEnabled(LOGGER,
                            "[{}] Recommend server is not in server list, ignore recommend server {}",
                            rpcClientConfig.name(), reconnectContext.serverInfo.getAddress());
                            reconnectContext.serverInfo = null;
                        }
                    }
                    //执行重新连接,onRequestFail等于true会执行健康检查,false创建新的连接
                    reconnect(reconnectContext.serverInfo, reconnectContext.onRequestFail);
                } catch (Throwable throwable) {
                    // Do nothing
                }
            }
        });
        
        Connection connectToServer = null;
        rpcClientStatus.set(RpcClientStatus.STARTING);
        int startUpRetryTimes = rpcClientConfig.retryTimes();
        while (startUpRetryTimes > 0 && connectToServer == null) {
            try {
                startUpRetryTimes--;
                //获取服务器地址信息
                ServerInfo serverInfo = nextRpcServer();
                //连接到服务器
                connectToServer = connectToServer(serverInfo);
            } catch (Throwable e) {
            }
        }
        
        if (connectToServer != null) {
			//设置连接状态和发送建立连接时间
            this.currentConnection = connectToServer;
            rpcClientStatus.set(RpcClientStatus.RUNNING);
            eventLinkedBlockingQueue.offer(new ConnectionEvent(ConnectionEvent.CONNECTED));
        } else {
            //启动失败异步启动
            switchServerAsync();
        }
        registerServerRequestHandler(new ConnectResetRequestHandler());
        // register client detection request.
        registerServerRequestHandler(request -> {
            if (request instanceof ClientDetectionRequest) {
                return new ClientDetectionResponse();
            }
            return null;
        });
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值