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() {
}
@Bean
public 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 */
@Deprecated
public 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 */
@Deprecated
protected 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 */
@Deprecated
protected Environment getEnvironment() {
return this.environment;
}
/** @deprecated */
@Deprecated
protected 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 */
@Deprecated
protected abstract int getConfiguredPort();
/** @deprecated */
@Deprecated
protected abstract void setConfiguredPort(int var1);
protected boolean shouldRegisterManagement() {
return this.getManagementPort() != null && ManagementServerPortUtils.isDifferent(this.context);
}
/** @deprecated */
@Deprecated
protected abstract Object getConfiguration();
protected abstract void register();
protected void registerManagement() {
}
protected abstract void deregister();
protected void deregisterManagement() {
}
protected abstract boolean isEnabled();
/** @deprecated */
@Deprecated
protected String getManagementServiceId() {
return this.context.getId() + ":management";
}
/** @deprecated */
@Deprecated
protected String getManagementServiceName() {
return this.getAppName() + ":management";
}
/** @deprecated */
@Deprecated
protected Integer getManagementPort() {
return ManagementServerPortUtils.getPort(this.context);
}
/** @deprecated */
@Deprecated
protected 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();
}
}
}
@PreDestroy
public 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 */
@Deprecated
public 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 读万卷书,不如行万里路,建议自己动手实际去看看,收获才是最多的!
注:本人能力有限,还请多多包涵,亦欢迎大佬指正错误!