spring-cloud-alibaba-nacos-discovery 老版本中如何调用nacos的
1. 整体结构:
2. 思考: 如果你来做,如何做client 向server注册服务:
1.2.1 读yml,或本地文件找到服务器地址,以及其他配置
1.2.2 向server注册服务
1.2.3 定期发送心跳
3. 源码跟踪
3.1查看spring 自动装配 spring.factories:
3.2 截图:
3.3 查看NacosDiscoveryAutoConfiguration类
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package com.alibaba.cloud.nacos;import com.alibaba.cloud.nacos.registry.NacosAutoServiceRegistration;
import com.alibaba.cloud.nacos.registry.NacosRegistration;
import com.alibaba.cloud.nacos.registry.NacosServiceRegistry;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled
@ConditionalOnClass(name = {"org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent"}
)
@ConditionalOnProperty(value = {"spring.cloud.service-registry.auto-registration.enabled"},matchIfMissing = true
)
@AutoConfigureAfter({AutoServiceRegistrationConfiguration.class, AutoServiceRegistrationAutoConfiguration.class})
public class NacosDiscoveryAutoConfiguration {public NacosDiscoveryAutoConfiguration() {}@Beanpublic NacosServiceRegistry nacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) {return new NacosServiceRegistry(nacosDiscoveryProperties);}@Bean@ConditionalOnBean({AutoServiceRegistrationProperties.class})public NacosRegistration nacosRegistration(NacosDiscoveryProperties nacosDiscoveryProperties, ApplicationContext context) {return new NacosRegistration(nacosDiscoveryProperties, context);}@Bean@ConditionalOnBean({AutoServiceRegistrationProperties.class})public NacosAutoServiceRegistration nacosAutoServiceRegistration(NacosServiceRegistry registry, AutoServiceRegistrationProperties autoServiceRegistrationProperties, NacosRegistration registration) {return new NacosAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration);}
}
3.3.1 注: 可看出重点是三个@Bean 注解的方法,三个对象放入spring 进入管理,我们需要依次查看三个对象,这里就不一一查看了,重点是NacosAutoServiceRegistration.class 。或者说入口是在NacosAutoServiceRegistration, 然后再看另外两个对象
3.4. NacosAutoServiceRegistration:
3.4.1 源码:
public class NacosAutoServiceRegistration extends AbstractAutoServiceRegistration<Registration> {private static final Logger log = LoggerFactory.getLogger(NacosAutoServiceRegistration.class);private NacosRegistration registration;public NacosAutoServiceRegistration(ServiceRegistry<Registration> serviceRegistry, AutoServiceRegistrationProperties autoServiceRegistrationProperties, NacosRegistration registration) {super(serviceRegistry, autoServiceRegistrationProperties);this.registration = registration;}/** @deprecated */@Deprecatedpublic void setPort(int port) {this.getPort().set(port);}protected NacosRegistration getRegistration() {if (this.registration.getPort() < 0 && this.getPort().get() > 0) {this.registration.setPort(this.getPort().get());}Assert.isTrue(this.registration.getPort() > 0, "service.port has not been set");return this.registration;}protected NacosRegistration getManagementRegistration() {return null;}protected void register() {if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {log.debug("Registration disabled.");} else {if (this.registration.getPort() < 0) {this.registration.setPort(this.getPort().get());}super.register();}}protected void registerManagement() {if (this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {super.registerManagement();}}protected int getConfiguredPort() {return this.getPort().get();}protected void setConfiguredPort(int port) {this.getPort().set(port);}protected Object getConfiguration() {return this.registration.getNacosDiscoveryProperties();}protected boolean isEnabled() {return this.registration.getNacosDiscoveryProperties().isRegisterEnabled();}protected String getAppName() {String appName = this.registration.getNacosDiscoveryProperties().getService();return StringUtils.isEmpty(appName) ? super.getAppName() : appName;}
}
3.4.2 没有发现如何启动,继续查看父类:
3.4.2.1 源码:
package org.springframework.cloud.client.serviceregistry;import org.springframework.cloud.client.discovery.AbstractDiscoveryLifecycle;public abstract class AbstractAutoServiceRegistration<R extends Registration> extends AbstractDiscoveryLifecycle implements AutoServiceRegistration {private final ServiceRegistry<R> serviceRegistry;private AutoServiceRegistrationProperties properties;/** @deprecated */@Deprecatedprotected AbstractAutoServiceRegistration(ServiceRegistry<R> serviceRegistry) {this.serviceRegistry = serviceRegistry;}protected AbstractAutoServiceRegistration(ServiceRegistry<R> serviceRegistry, AutoServiceRegistrationProperties properties) {this.serviceRegistry = serviceRegistry;this.properties = properties;}protected ServiceRegistry<R> getServiceRegistry() {return this.serviceRegistry;}protected abstract R getRegistration();protected abstract R getManagementRegistration();protected void register() {this.serviceRegistry.register(this.getRegistration());}protected void registerManagement() {R registration = this.getManagementRegistration();if (registration != null) {this.serviceRegistry.register(registration);}}protected void deregister() {this.serviceRegistry.deregister(this.getRegistration());}protected void deregisterManagement() {R registration = this.getManagementRegistration();if (registration != null) {this.serviceRegistry.deregister(registration);}}public void stop() {if (this.getRunning().compareAndSet(true, false) && this.isEnabled()) {this.deregister();if (this.shouldRegisterManagement()) {this.deregisterManagement();}this.serviceRegistry.close();}}protected boolean shouldRegisterManagement() {return this.properties != null && !this.properties.isRegisterManagement() ? false : super.shouldRegisterManagement();}
}
3.4.2.2 注:
注意此时包名换了。现在是spring框架源码,并且继承了AbstractDiscoveryLifecycle
3.5 查看 AbstractDiscoveryLifecycle
3.5.1 AbstractDiscoveryLifecycle源码:
@Deprecated
public abstract class AbstractDiscoveryLifecycle implements DiscoveryLifecycle, ApplicationContextAware, ApplicationListener<EmbeddedServletContainerInitializedEvent> {private static final Log logger = LogFactory.getLog(AbstractDiscoveryLifecycle.class);private boolean autoStartup = true;private AtomicBoolean running = new AtomicBoolean(false);private int order = 0;private ApplicationContext context;private Environment environment;private AtomicInteger port = new AtomicInteger(0);public AbstractDiscoveryLifecycle() {}protected ApplicationContext getContext() {return this.context;}public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.context = applicationContext;this.environment = this.context.getEnvironment();}/** @deprecated */@Deprecatedprotected Environment getEnvironment() {return this.environment;}/** @deprecated */@Deprecatedprotected AtomicInteger getPort() {return this.port;}public boolean isAutoStartup() {return this.autoStartup;}public void stop(Runnable callback) {try {this.stop();} catch (Exception var3) {logger.error("A problem occurred attempting to stop discovery lifecycle", var3);}callback.run();}public void start() {if (!this.isEnabled()) {if (logger.isDebugEnabled()) {logger.debug("Discovery Lifecycle disabled. Not starting");}} else {if (this.port.get() != 0 && this.getConfiguredPort() == 0) {this.setConfiguredPort(this.port.get());}if (!this.running.get() && this.getConfiguredPort() > 0) {this.register();if (this.shouldRegisterManagement()) {this.registerManagement();}this.context.publishEvent(new InstanceRegisteredEvent(this, this.getConfiguration()));this.running.compareAndSet(false, true);}}}/** @deprecated */@Deprecatedprotected abstract int getConfiguredPort();/** @deprecated */@Deprecatedprotected abstract void setConfiguredPort(int var1);protected boolean shouldRegisterManagement() {return this.getManagementPort() != null && ManagementServerPortUtils.isDifferent(this.context);}/** @deprecated */@Deprecatedprotected abstract Object getConfiguration();protected abstract void register();protected void registerManagement() {}protected abstract void deregister();protected void deregisterManagement() {}protected abstract boolean isEnabled();/** @deprecated */@Deprecatedprotected String getManagementServiceId() {return this.context.getId() + ":management";}/** @deprecated */@Deprecatedprotected String getManagementServiceName() {return this.getAppName() + ":management";}/** @deprecated */@Deprecatedprotected Integer getManagementPort() {return ManagementServerPortUtils.getPort(this.context);}/** @deprecated */@Deprecatedprotected String getAppName() {return this.environment.getProperty("spring.application.name", "application");}public void stop() {if (this.running.compareAndSet(true, false) && this.isEnabled()) {this.deregister();if (this.shouldRegisterManagement()) {this.deregisterManagement();}}}@PreDestroypublic void destroy() {this.stop();}public boolean isRunning() {return this.running.get();}protected AtomicBoolean getRunning() {return this.running;}public int getOrder() {return this.order;}public int getPhase() {return 0;}// ***************************************************************// 重点// *************************************************************** /** @deprecated */@Deprecatedpublic void onApplicationEvent(EmbeddedServletContainerInitializedEvent event) {if (!"management".equals(event.getApplicationContext().getNamespace())) {this.port.compareAndSet(0, event.getEmbeddedServletContainer().getPort());this.start();}}
}
3.5.2 注:
AbstractDiscoveryLifecycle抽象类继承了ApplicationListener该类需要实现方法onApplicationEvent,且此方法就在AbstractDiscoveryLifecycle。 该方法调用了this.start()
3.6 查看this.start()
3.6.1 源码:
public void start() {if (!this.isEnabled()) {if (logger.isDebugEnabled()) {logger.debug("Discovery Lifecycle disabled. Not starting");}} else {if (this.port.get() != 0 && this.getConfiguredPort() == 0) {this.setConfiguredPort(this.port.get());}if (!this.running.get() && this.getConfiguredPort() > 0) {this.register();if (this.shouldRegisterManagement()) {this.registerManagement();}// 这个地方发布了一个服务注册事件,订阅不知道在哪 ==!this.context.publishEvent(new InstanceRegisteredEvent(this, this.getConfiguration()));this.running.compareAndSet(false, true);}}}
3.6.2 注: start()方法内,调用了this.register() 并且此方法仍旧在AbstractDiscoveryLifecycle类中,且在spring 框架内,说明spring 留了一个口子(spi)来帮助实现服务注册功能,自己想做服务注册,只要继承AbstractDiscoveryLifecycle 重写register方法即可!
3.7 点击this.register() : 发现仍在AbstractDiscoveryLifecycle,且是个抽象类!并没有具体实现!
pr4otected abstract void register();
3.8 idea 点击实现类: 找到NacosAutoServiceREgistration 实现类
3.9 实现方法:
protected void register() {if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {log.debug("Registration disabled.");} else {if (this.registration.getPort() < 0) {this.registration.setPort(this.getPort().get());}super.register();}}
4.0 继续跟踪super.register()
public abstract class AbstractAutoServiceRegistration<R extends Registration> extends AbstractDiscoveryLifecycle implements AutoServiceRegistration {// *****省略protected void register() {this.serviceRegistry.register(this.getRegistration());}}
4.1 this.serviceRegistry.register(this.getRegistration());
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.cloud.client.serviceregistry;public interface ServiceRegistry<R extends Registration> {void register(R var1);void deregister(R var1);void close();void setStatus(R var1, String var2);<T> T getStatus(R var1);
}
4.2 点击register 实现,则 发现为NacosServiceRegistry 实现类
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package com.alibaba.cloud.nacos.registry;import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import java.util.Iterator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.util.StringUtils;public class NacosServiceRegistry implements ServiceRegistry<Registration> {private static final Logger log = LoggerFactory.getLogger(NacosServiceRegistry.class);private final NacosDiscoveryProperties nacosDiscoveryProperties;private final NamingService namingService;public NacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) {this.nacosDiscoveryProperties = nacosDiscoveryProperties;this.namingService = nacosDiscoveryProperties.namingServiceInstance();}// NacosServiceRegistry 实现spring 框架类ServiceRegistry的register方法 public void register(Registration registration) {if (StringUtils.isEmpty(registration.getServiceId())) {log.warn("No service to register for nacos client...");} else {String serviceId = registration.getServiceId();Instance instance = this.getNacosInstanceFromRegistration(registration);try {this.namingService.registerInstance(serviceId, instance);log.info("nacos registry, {} {}:{} register finished", new Object[]{serviceId, instance.getIp(), instance.getPort()});} catch (Exception var5) {log.error("nacos registry, {} register failed...{},", new Object[]{serviceId, registration.toString(), var5});}}}public void deregister(Registration registration) {log.info("De-registering from Nacos Server now...");if (StringUtils.isEmpty(registration.getServiceId())) {log.warn("No dom to de-register for nacos client...");} else {NamingService namingService = this.nacosDiscoveryProperties.namingServiceInstance();String serviceId = registration.getServiceId();try {namingService.deregisterInstance(serviceId, registration.getHost(), registration.getPort(), this.nacosDiscoveryProperties.getClusterName());} catch (Exception var5) {log.error("ERR_NACOS_DEREGISTER, de-register failed...{},", registration.toString(), var5);}log.info("De-registration finished.");}}public void close() {}public void setStatus(Registration registration, String status) {if (!status.equalsIgnoreCase("UP") && !status.equalsIgnoreCase("DOWN")) {log.warn("can't support status {},please choose UP or DOWN", status);} else {String serviceId = registration.getServiceId();Instance instance = this.getNacosInstanceFromRegistration(registration);if (status.equalsIgnoreCase("DOWN")) {instance.setEnabled(false);} else {instance.setEnabled(true);}try {this.nacosDiscoveryProperties.namingMaintainServiceInstance().updateInstance(serviceId, instance);} catch (Exception var6) {throw new RuntimeException("update nacos instance status fail", var6);}}}public Object getStatus(Registration registration) {String serviceName = registration.getServiceId();try {List<Instance> instances = this.nacosDiscoveryProperties.namingServiceInstance().getAllInstances(serviceName);Iterator var4 = instances.iterator();while(var4.hasNext()) {Instance instance = (Instance)var4.next();if (instance.getIp().equalsIgnoreCase(this.nacosDiscoveryProperties.getIp()) && instance.getPort() == this.nacosDiscoveryProperties.getPort()) {return instance.isEnabled() ? "UP" : "DOWN";}}} catch (Exception var6) {log.error("get all instance of {} error,", serviceName, var6);}return null;}private Instance getNacosInstanceFromRegistration(Registration registration) {Instance instance = new Instance();instance.setIp(registration.getHost());instance.setPort(registration.getPort());instance.setWeight((double)this.nacosDiscoveryProperties.getWeight());instance.setClusterName(this.nacosDiscoveryProperties.getClusterName());instance.setMetadata(registration.getMetadata());return instance;}
}
4.2.1 调用链路实现闭环
1. spring boot 自动装配,META-INF/spring.factories
2. 第一个就是NacosDiscoveryAutoConfiguration 且该类创建三个Bean对象(NacosServiceRegistry, NacosRegistration,NacosAutoServiceRegistration)3. 核心NacosAutoServiceRegistration类继承AbstractAutoServiceRegistration
4. AbstractAutoServiceRegistration为spring 框架内容,且继承AbstractDiscoveryLifecycle
5. AbstractDiscoveryLifecycle实现了ApplicationListener的onApplicationEvent方法
6. onApplicationEvent内调用了this.start();
7. this.start 调用了this.register
8. NacosAutoServiceRegistration实现了this.register 并调用方法super.register()
9. 调用父类register(),此时为spring 框架方法, 且调用了this.serviceRegistry.register(this.getRegistration());
10.register为接口spring未提供实现类,由nacos的NacosServiceRegistry
类实现register方法
11. NacosServiceRegistry类register方法内调用了this.namingService.registerInstance(serviceId, instance);
12. 最终到达ncos源码中client 模块的注册服务方法
13. 为NacosNamingServiceregis.registerInstance(serviceId, instance);
5. 总结:
5.1 本文主要讲了spring cloud alibaba 的starter模块下的 discovery模块,讲了客户端依赖了discovery 之后,它是是如何步一步到达nacos源码过程
5.2 读了源码后,发现spring 已为服务注册留下了spi !配合spring boot自动装配,自己也可以实现一个client, server。继承AbstractAutoServiceRegistration 以及实现register()等
5.3 读万卷书,不如行万里路,建议自己动手实际去看看,收获才是最多的!
注:本人能力有限,还请多多包涵,亦欢迎大佬指正错误!