搭建环境
搭建Nacos服务端环境
从github上下载nacos1.4源码下来:https://github.com/alibaba/nacos
下载下来,源码编译好,直接idea运行 com.alibaba.nacos.Nacos
类就行:
那我怎么知道这个类就是启动类呢?
我们可以分析nacos的启动脚本,会java -jar名称为
nacos-server.jar
的jar包,然后解压该jar,看MANIFEST.MF
文件,里面就描述了start-class为com.alibaba.nacos.Nacos
类
在本篇文章中不需要研究nacos server端的源码,但是后面需要,所以就提前搭建好这个环境。
搭建nacos client环境
准备一个简单的springboot 项目:
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
主启动类:
@EnableDiscoveryClient
@SpringBootApplication
public class NacosMainApplication {
public static void main(String[] args) {
SpringApplication.run(NacosMainApplication.class, args);
}
}
bootstrap.yml
spring:
application:
name: nacos-test
cloud:
nacos:
discovery:
server-addr: 2.0.0.1:8848
#设置命名空间
namespace: public
#设置服务实例是否持久化,true为AP模式,false为CP模式
ephemeral: true
server:
port: 10000
直接启动,发现服务可以注册到nacos:
源码分析
spring cloud commons服务注册规范
在我们引入nacos-discovery的starter的时候,会自动引入spring-cloud-commons
,而该包中就有spring cloud
对微服务制定的一些接口规范,如果想要接入springcloud,就必须实现该规范。
本文是将客户端注册源码,所以我们就先可以了解serviceregistry
服务注册的规范:
主要有两大核心接口:Registration
和ServiceRegistry
Registration
:表示需要被注册的服务实例ServiceRegistry
:服务注册对象,通过此对象,可以向注册中心注册服务实例。
此外还有一个重要的自动注册器:AbstractAutoServiceRegistration
,spring cloud的想法是第三方继承了抽象类并实现了注册方法,当前服务就可以自动发起注册。
那么是怎么做的呢:先看类图:
比较引人注意的就是实现了ApplicationListener
接口。我们接下来看源码:
@Override
@SuppressWarnings("deprecation")
//监听WebServerInitializedEvent事件
//该事件会在web容器启动完成后发出
public void onApplicationEvent(WebServerInitializedEvent event) {
//执行bind方法
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());
//执行start方法
this.start();
}
public void start() {
if (!isEnabled()) {
if (logger.isDebugEnabled()) {
logger.debug("Discovery Lifecycle disabled. Not starting");
}
return;
}
// only initialize if nonSecurePort is greater than 0 and it isn't already running
// because of containerPortInitializer below
if (!this.running.get()) {
//发布服务实例注册前事件
this.context.publishEvent(
new InstancePreRegisteredEvent(this, getRegistration()));
//调用注册方法
register();
if (shouldRegisterManagement()) {
registerManagement();
}
//发布服务实例注册完成事件
this.context.publishEvent(
new InstanceRegisteredEvent<>(this, getConfiguration()));
this.running.compareAndSet(false, true);
}
}
protected void register() {
//执行serviceRegistry的register注册方法,serviceRegistry需要第三方自行实现
this.serviceRegistry.register(getRegistration());
}
//获取到服务注册实例对象
protected abstract R getRegistration();
nacos对规范的实现
NacosAutoServiceRegistration
是对AbstractAutoServiceRegistration
抽象类的实现比较简单,而该类被自动注册类NacosServiceRegistryAutoConfiguration
所引入:
public class NacosServiceRegistryAutoConfiguration {
//创建NacosServiceRegistry,实现了ServiceRegistry接口,用于客户端向nacos服务端注册服务实例
@Bean
public NacosServiceRegistry nacosServiceRegistry(
NacosDiscoveryProperties nacosDiscoveryProperties) {
return new NacosServiceRegistry(nacosDiscoveryProperties);
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
//创建NacosRegistration,即所需要注册的服务实例对象
public NacosRegistration nacosRegistration(
ObjectProvider<List<NacosRegistrationCustomizer>> registrationCustomizers,
NacosDiscoveryProperties nacosDiscoveryProperties,
ApplicationContext context) {
return new NacosRegistration(registrationCustomizers.getIfAvailable(),
nacosDiscoveryProperties, context);
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
//创建NacosAutoServiceRegistration
public NacosAutoServiceRegistration nacosAutoServiceRegistration(
NacosServiceRegistry registry,
AutoServiceRegistrationProperties autoServiceRegistrationProperties,
NacosRegistration registration) {
return new NacosAutoServiceRegistration(registry,
autoServiceRegistrationProperties, registration);
}
}
所以我们只需要研究NacosServiceRegistry
类的register
方法就能知道注册的源码了:
@Override
public void register(Registration registration) {
if (StringUtils.isEmpty(registration.getServiceId())) {
log.warn("No service to register for nacos client...");
return;
}
//获取到NamingService,实际上nacos注册是靠NamingService
NamingService namingService = namingService();
//获取服务id
String serviceId = registration.getServiceId();
//获取group
String group = nacosDiscoveryProperties.getGroup();
//创建Instance对象,无非就是把registration的属性值设置到Instance中
Instance instance = getNacosInstanceFromRegistration(registration);
try {
//真正执行注册方法,注册Instance实例
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);
}
}
private NamingService namingService() {
//从给定的Properties获取到NamingService
//本质上就是获取Properties的属性内容,并设置到NacosNamingService成员变量中,做一些初始化属性的操作
return nacosServiceManager
.getNamingService(nacosDiscoveryProperties.getNacosProperties());
}
再看registerInstance
源码:
@Override
public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
//校验Instance信息是否合法
NamingUtils.checkInstanceIsLegal(instance);
String groupedServiceName = NamingUtils.getGroupedName(serviceName, groupName);
//判断实例是否是临时的,默认为true
if (instance.isEphemeral()) {
BeatInfo beatInfo = beatReactor.buildBeatInfo(groupedServiceName, instance);
//添加心跳任务(这个心跳任务我们以后再说)
beatReactor.addBeatInfo(groupedServiceName, beatInfo);
}
//调用NamingProxy的registerService进行注册
serverProxy.registerService(groupedServiceName, groupName, instance);
}
代码继续往里面走,这里就已经初见端倪了,直接调用rest请求进行注册的。
public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {
NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance: {}", namespaceId, serviceName,
instance);
//这里构建了一些请求参数
final Map<String, String> params = new HashMap<String, String>(16);
params.put(CommonParams.NAMESPACE_ID, namespaceId);
params.put(CommonParams.SERVICE_NAME, serviceName);
params.put(CommonParams.GROUP_NAME, groupName);
params.put(CommonParams.CLUSTER_NAME, instance.getClusterName());
params.put("ip", instance.getIp());
params.put("port", String.valueOf(instance.getPort()));
params.put("weight", String.valueOf(instance.getWeight()));
params.put("enable", String.valueOf(instance.isEnabled()));
params.put("healthy", String.valueOf(instance.isHealthy()));
params.put("ephemeral", String.valueOf(instance.isEphemeral()));
params.put("metadata", JacksonUtils.toJson(instance.getMetadata()));
//执行POST请求方法
//这里nacosUrlInstance拼起来就是:/nacos/v1/ns/instance
reqApi(UtilAndComs.nacosUrlInstance, params, HttpMethod.POST);
}
reqApi
方法在往里面走,走到callServer
方法:
public String callServer(String api, Map<String, String> params, Map<String, String> body, String curServer,
String method) throws NacosException {
long start = System.currentTimeMillis();
long end = 0;
injectSecurityInfo(params);
Header header = builderHeader();
String url;
if (curServer.startsWith(UtilAndComs.HTTPS) || curServer.startsWith(UtilAndComs.HTTP)) {
url = curServer + api;
} else {
if (!IPUtil.containsPort(curServer)) {
curServer = curServer + IPUtil.IP_PORT_SPLITER + serverPort;
}
url = NamingHttpClientManager.getInstance().getPrefix() + curServer + api;
}
try {
//执行nacosRestTemplate的exchangeForm,发送http请求
//nacosRestTemplate是Nacos自己实现的http 客户端,大家可以把他看作spring实现的RestTemplate,作用都是一样的
HttpRestResult<String> restResult = nacosRestTemplate
.exchangeForm(url, header, Query.newInstance().initParams(params), body, method, String.class);
end = System.currentTimeMillis();
MetricsMonitor.getNamingRequestMonitor(method, url, String.valueOf(restResult.getCode()))
.observe(end - start);
if (restResult.ok()) {
return restResult.getData();
}
if (HttpStatus.SC_NOT_MODIFIED == restResult.getCode()) {
return StringUtils.EMPTY;
}
throw new NacosException(restResult.getCode(), restResult.getMessage());
} catch (Exception e) {
NAMING_LOGGER.error("[NA] failed to request", e);
throw new NacosException(NacosException.SERVER_ERROR, e);
}
}
客户端注册方法到这里全部走完。
因为客户端发送POST
请求进行注册,所以服务端一定有对应的Controller
进行处理。
而处理注册请求的Controller
就是com.alibaba.nacos.naming.controllers.InstanceController
,在之前下载的nacos server端的源码中:
后面我会对nacos1.4服务端注册服务实例源码进行解析。
标签:Nacos1.4,String,nacos,instance,源码,params,注册,客户端 From: https://www.cnblogs.com/wwjj4811/p/17008755.html