spring cloud针对服务注册和发现仅提供了抽象(都封装在spring-cloud-commons包里),常见的实现有eureka、nacos等组件,这里主要以nacos为例进行源码分析,本文代码依赖版本
spring-cloud | spring-cloud-alibaba |
---|---|
Hoxton.SR8 | 2.2.5.RELEASE |
1. 服务注册的核心接口
AutoServiceRegistration
接口:服务注册配置类,spring针对该接口实现了一个抽象类AbstractAutoServiceRegistration
是服务注册的触发类。
ServiceRegistry
接口:负责具体的服务注册
Registration
接口:主要定义服务注册所需要的一些信息,如:本服务的服务名、ip地址端口号、元数据等等。
2. 从@EnableDiscoveryClient说起
1
2
3
4
5@Import(EnableDiscoveryClientImportSelector.class) public @interface EnableDiscoveryClient { boolean autoRegister() default true; }
主要引入了EnableDiscoveryClientImportSelector
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18@Order(Ordered.LOWEST_PRECEDENCE - 100) public class EnableDiscoveryClientImportSelector extends SpringFactoryImportSelector<EnableDiscoveryClient> { @Override public String[] selectImports(AnnotationMetadata metadata) { String[] imports = super.selectImports(metadata); AnnotationAttributes attributes = AnnotationAttributes.fromMap( metadata.getAnnotationAttributes(getAnnotationClass().getName(), true)); boolean autoRegister = attributes.getBoolean("autoRegister"); if (autoRegister) { List<String> importsList = new ArrayList<>(Arrays.asList(imports)); importsList.add( "org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration"); imports = importsList.toArray(new String[0]); } ......省略后面代码..... }
从上面可以看到默认开启了注册功能,向spring中注册了AutoServiceRegistrationConfiguration
类。
1
2
3
4
5
6
7@Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(AutoServiceRegistrationProperties.class) @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) public class AutoServiceRegistrationConfiguration { }
这类啥也没,就启用了AutoServiceRegistrationProperties
配置。
一脸懵逼…………………………
3. AutoServiceRegistrationAutoConfiguration配置类
继续寻找突破口,在spring-cloud-commons的spring.factories文件里发现EnableAutoConfiguration的参数里有AutoServiceRegistrationAutoConfiguration。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18@Configuration(proxyBeanMethods = false) @Import(AutoServiceRegistrationConfiguration.class) @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) public class AutoServiceRegistrationAutoConfiguration { @Autowired(required = false) private AutoServiceRegistration autoServiceRegistration; @Autowired private AutoServiceRegistrationProperties properties; @PostConstruct protected void init() { if (this.autoServiceRegistration == null && this.properties.isFailFast()) { throw new IllegalStateException("Auto Service Registration has " + "been requested, but there is no AutoServiceRegistration bean"); } } }
发现注入的有AutoServiceRegistration
接口,并在构造完成后对AutoServiceRegistration
做了不为空的校验.
4. Nacos服务注册接口的实现
4.1. NacosAutoServiceRegistration实现类
NacosAutoServiceRegistration
继承AbstractAutoServiceRegistration
类。
先看看AbstractAutoServiceRegistration
类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33public abstract class AbstractAutoServiceRegistration<R extends Registration> implements AutoServiceRegistration, ApplicationContextAware, ApplicationListener<WebServerInitializedEvent> { public void onApplicationEvent(WebServerInitializedEvent event) { bind(event);//关键步骤一 } @Deprecated public void bind(WebServerInitializedEvent event) { ApplicationContext context = event.getApplicationContext(); if (context instanceof ConfigurableWebServerApplicationContext) { if ("management".equals(((ConfigurableWebServerApplicationContext) context) .getServerNamespace())) { return; } } this.port.compareAndSet(0, event.getWebServer().getPort()); this.start();//关键步骤二 } public void start() { …………………… // only initialize if nonSecurePort is greater than 0 and it isn't already running // because of containerPortInitializer below if (!this.running.get()) { …………………… register();//关键步骤三 …………………… } } protected void register() { this.serviceRegistry.register(getRegistration());//关键步骤四 } }
顺着上面的关键步骤可以知道spring在web容器初始化完成后会出发服务注册的操作。接着看具体实现类NacosAutoServiceRegistration
1
2
3
4
5
6
7
8
9
10
11
12
13public 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; } }
从构造方法可以看出已将serviceRegistry和registration赋值。
4.2. NacosServiceRegistry类和NacosRegistration类
NacosServiceRegistry
实现接口ServiceRegistry
,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27public NacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) { this.nacosDiscoveryProperties = nacosDiscoveryProperties; } @Override public void register(Registration registration) { if (StringUtils.isEmpty(registration.getServiceId())) { log.warn("No service to register for nacos client..."); return; } NamingService namingService = namingService(); String serviceId = registration.getServiceId(); String group = nacosDiscoveryProperties.getGroup(); Instance instance = getNacosInstanceFromRegistration(registration); try { namingService.registerInstance(serviceId, group, instance); log.info("nacos registry, {} {} {}:{} register finished", group, serviceId, instance.getIp(), instance.getPort()); } catch (Exception e) { log.error("nacos registry, {} register failed...{},", serviceId, registration.toString(), e); // rethrow a RuntimeException if the registration is failed. // issue : https://github.com/alibaba/spring-cloud-alibaba/issues/1132 rethrowRuntimeException(e); } }
这个类实现了nacos的注册逻辑
4.3. Nacos服务注册接口实现类的创建
上面讲了Nacos服务注册接口实现类的作用,在哪创建的呢?
在spring-cloud-starter-alibaba-nacos-discovery
包的spring.factories 里有
1
2
3
4
5
6
7
8
9
10org.springframework.boot.autoconfigure.EnableAutoConfiguration= com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration, com.alibaba.cloud.nacos.ribbon.RibbonNacosAutoConfiguration, com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration, com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration, com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration, com.alibaba.cloud.nacos.discovery.reactive.NacosReactiveDiscoveryClientConfiguration, com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfiguration, com.alibaba.cloud.nacos.NacosServiceAutoConfiguration
打开NacosServiceRegistryAutoConfiguration
类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) @AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class, AutoServiceRegistrationAutoConfiguration.class, NacosDiscoveryAutoConfiguration.class }) public class NacosServiceRegistryAutoConfiguration { @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); } }
可以看到引入该包后后,在spring.cloud.service-registry.auto-registration.enabled
开关开启后就会自动创建
5. nacos的心跳机制(nacos-client-1.4.1)
服务注册到服务中心后,nacos注册中心维护了一个客户端的列表。
看看BeatReactor
这个线程类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54public class BeatReactor implements Closeable { …………………………………… class BeatTask implements Runnable { BeatInfo beatInfo; public BeatTask(BeatInfo beatInfo) { this.beatInfo = beatInfo; } @Override public void run() { if (beatInfo.isStopped()) { return; } long nextTime = beatInfo.getPeriod(); try { JsonNode result = serverProxy.sendBeat(beatInfo, BeatReactor.this.lightBeatEnabled); long interval = result.get("clientBeatInterval").asLong(); boolean lightBeatEnabled = false; if (result.has(CommonParams.LIGHT_BEAT_ENABLED)) { lightBeatEnabled = result.get(CommonParams.LIGHT_BEAT_ENABLED).asBoolean(); } BeatReactor.this.lightBeatEnabled = lightBeatEnabled; if (interval > 0) { nextTime = interval; } int code = NamingResponseCode.OK; if (result.has(CommonParams.CODE)) { code = result.get(CommonParams.CODE).asInt(); } if (code == NamingResponseCode.RESOURCE_NOT_FOUND) { Instance instance = new Instance(); instance.setPort(beatInfo.getPort()); instance.setIp(beatInfo.getIp()); instance.setWeight(beatInfo.getWeight()); instance.setMetadata(beatInfo.getMetadata()); instance.setClusterName(beatInfo.getCluster()); instance.setServiceName(beatInfo.getServiceName()); instance.setInstanceId(instance.getInstanceId()); instance.setEphemeral(true); try { serverProxy.registerService(beatInfo.getServiceName(), NamingUtils.getGroupName(beatInfo.getServiceName()), instance); } catch (Exception ignore) { } } } catch (NacosException ex) { NAMING_LOGGER.error("[CLIENT-BEAT] failed to send beat: {}, code: {}, msg: {}", JacksonUtils.toJson(beatInfo), ex.getErrCode(), ex.getErrMsg()); } executorService.schedule(new BeatTask(beatInfo), nextTime, TimeUnit.MILLISECONDS); } } ……………………………… }
executorService
为ScheduledExecutorService
,定时的执行BeatTask
这个任务,心跳的间隔时间从心跳接口中获取,当前版本为5秒一次。如果心跳接口返回没有发现该服务nacaos会再次注册服务。
最后
以上就是怡然金鱼最近收集整理的关于spring cloud 服务注册源码分析-nacos的全部内容,更多相关spring内容请搜索靠谱客的其他文章。
发表评论 取消回复