服务端注册会分三块讲解
- 主流程讲解
- client管理
- 注册过程中发布的事件
方法上的 @CanDistro 和 @Secured注解后面再作说明
这里的Instance 对象的属性跟 客户端篇 的Instance 对象的属性是一样的这里部赘述
@RequestMapping(UtilsAndCommons.NACOS_NAMING_CONTEXT + UtilsAndCommons.NACOS_NAMING_INSTANCE_CONTEXT)
public class InstanceController {
@CanDistro
@PostMapping
@Secured(action = ActionTypes.WRITE)
public String register(HttpServletRequest request) throws Exception {
//读取请求的namespaceId字段值 默认时public
final String namespaceId = WebUtils
.optional(request, CommonParams.NAMESPACE_ID,
Constants.DEFAULT_NAMESPACE_ID);
//读取请求的服务名称字段值 格式要求groupname@@servicename
final String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
//服务名称格式校验
NamingUtils.checkServiceNameFormat(serviceName);
//封装Instance 对象
final Instance instance = HttpRequestInstanceBuilder.newBuilder()
.setDefaultInstanceEphemeral(
switchDomain.isDefaultInstanceEphemeral()).
setRequest(request).build();
//这里 getInstanceOperator() 得到的是 InstanceOperatorClientImpl 类型对象
getInstanceOperator().registerInstance(namespaceId, serviceName, instance);
return "ok";
}
}
需要注意的是 构建instance 对象时instanceId 的生成逻辑
格式比如: ip#port#clusterName#serviceName
public class HttpRequestInstanceBuilder {
...
//设置instanceid
private void setInstanceId(Instance instance) {
DefaultInstanceIdGenerator idGenerator = new
DefaultInstanceIdGenerator(instance.getServiceName(),
instance.getClusterName(), instance.getIp(), instance.getPort());
instance.setInstanceId(idGenerator.generateInstanceId());
}
...
}
//instance id 生成器
public class DefaultInstanceIdGenerator implements IdGenerator {
public static final String ID_DELIMITER = "#";
public String generateInstanceId() {
return ip + ID_DELIMITER + port + ID_DELIMITER + clusterName + ID_DELIMITER +
serviceName;
}
}
public class InstanceOperatorClientImpl implements InstanceOperator {
@Override
public void registerInstance(String namespaceId, String serviceName, Instance instance)
{
//是否时临时实例 目前为止我们的实例都是临时的
boolean ephemeral = instance.isEphemeral();
//生成一个客户端id 用ip 和 端口表示一个客户端 格式ip#port
String clientId = IpPortBasedClient.getClientId(instance.toInetAddr(), ephemeral);
//根据客户端id创建客户端
createIpPortClientIfAbsent(clientId);
//创建一个服务
Service service = getService(namespaceId, serviceName, ephemeral);
//clientOprationService 这里的类型时 ClientOperationServiceProxy 代理类
clientOperationService.registerInstance(service, instance, clientId);
}
}
public class Service {
...
private Service(String namespace, String group, String name, boolean ephemeral) {
this.namespace = namespace;
this.group = group;
this.name = name;
this.ephemeral = ephemeral;
revision = new AtomicLong();
lastUpdatedTime = System.currentTimeMillis();
}
...
}
这一步生成了client id ,并创建了client。下面是官方对client的注释:
AbstractClient:The abstract concept of the client stored by on the server of Nacos naming module. It is used to store which services the client has published and subscribed。 IpPortBasedClient:The client is bind to the ip and port users registered. It's a abstract content to simulate the tcp session client 下一章节详细解读client. ClientOperationServiceProxy 是一个代理类他背后的逻辑是根据实例是否是临时节点选择相应的处理类完成实例注册 Service:不会记录ip port等信息 revision\lastUpdatedTime 这两个字段目前都是赋予初始值.等后面使用到的时候再做了解
public class ClientOperationServiceProxy {
//根据实例的持久化特性选择不同的处理类完成注册实例
@Override
public void registerInstance(Service service, Instance instance, String clientId) {
final ClientOperationService operationService =
chooseClientOperationService(instance);
//operationService 在这里的类型是: EphemeralClientOperationService
operationService.registerInstance(service, instance, clientId);
}
//临时节点使用 ephemeralClientOperationService
//持久化节点使用 persistentClientOperationService
private ClientOperationService chooseClientOperationService(final Instance instance) {
return instance.isEphemeral() ? ephemeralClientOperationService :
persistentClientOperationService;
}
}
public class EphemeralClientOperationServiceImpl implements ClientOperationService {
@Override
public void registerInstance(Service service, Instance instance, String clientId) {
//先检查该服务是否在服务管理器中注册过么有就注册
Service singleton = ServiceManager.getInstance().getSingleton(service);
...
//获取之前注册过的IpPortBasedClient对象
Client client = clientManager.getClient(clientId);
...
//从instance对象创建InstancePublishInfo
//注意包括ip port healthy 3个属性 是instance的属性的子集
InstancePublishInfo instanceInfo = getPublishInfo(instance);
client.addServiceInstance(singleton, instanceInfo);
client.setLastUpdatedTime();
//注册完成发布事件
NotifyCenter.publishEvent(new
ClientOperationEvent.ClientRegisterServiceEvent(singleton, clientId));
NotifyCenter.publishEvent(new MetadataEvent.InstanceMetadataEvent(singleton,
instanceInfo.getMetadataId(), false));
}
}
public class AbstractClient {
//记录客户端上发布的服务信息
protected final ConcurrentHashMap publishers = new ConcurrentHashMap<>(16, 0.75f, 1);
//...
protected final ConcurrentHashMap subscribers = new ConcurrentHashMap<>(16, 0.75f, 1);
....
@Override
public boolean addServiceInstance(Service service, InstancePublishInfo
instancePublishInfo) {
// 客户端务发布服务实例布信息
if (null == publishers.put(service, instancePublishInfo)) {
MetricsMonitor.incrementInstanceCount();
}
//统一事件中心:客户端变化事件
NotifyCenter.publishEvent(new ClientEvent.ClientChangedEvent(this));
return true;
....
}
}
核心流程逻辑比较简单注意包括下面几个步骤:
1、创建Instance
2、创建Client
3、创建Service
4、Client 添加注册实例
5、发布变更事件
下一章节我们介绍Client