上一篇我们说到NotifyCenter
,讲解了整个事件通知中心是如何通过巧妙的设计,让各个事件的生产者和消费者连接起来的。没看过的小伙伴可以点击这里进行查看。
本篇我们跟随这事件的路线,跟踪下订阅者获取到事件后,是如何进行处理的。
首先我们回顾一下,在注册的时候,服务端通过这个类,发布了几个事件,代码出处在com.alibaba.nacos.naming.remote.rpc.handler.InstanceRequestHandler#registerInstance
分别如下:
private InstanceResponse registerInstance(Service service, InstanceRequest request, RequestMeta meta)
throws NacosException {
// 注册实例
clientOperationService.registerInstance(service, request.getInstance(), meta.getConnectionId());
// 发布注册实例跟踪事件
NotifyCenter.publishEvent(new RegisterInstanceTraceEvent(System.currentTimeMillis(),
meta.getClientIp(), true, service.getNamespace(), service.getGroup(), service.getName(),
request.getInstance().getIp(), request.getInstance().getPort()));
// 对rpcClient进行应答
return new InstanceResponse(NamingRemoteConstants.REGISTER_INSTANCE);
}
public void registerInstance(Service service, Instance instance, String clientId) throws NacosException {
NamingUtils.checkInstanceIsLegal(instance);
// 获取单例的服务
Service singleton = ServiceManager.getInstance().getSingleton(service);
if (!singleton.isEphemeral()) {
throw new NacosRuntimeException(NacosException.INVALID_PARAM,
String.format("Current service %s is persistent service, can't register ephemeral instance.",
singleton.getGroupedServiceName()));
}
// 通过clientId获取一个客户端的处理类
Client client = clientManager.getClient(clientId);
if (!clientIsLegal(client, clientId)) {
return;
}
InstancePublishInfo instanceInfo = getPublishInfo(instance);
// 存放注册信息
client.addServiceInstance(singleton, instanceInfo);
client.setLastUpdatedTime();
client.recalculateRevision();
// 发布注册事件
NotifyCenter.publishEvent(new ClientOperationEvent.ClientRegisterServiceEvent(singleton, clientId));
// 发布内容信息事件
NotifyCenter
.publishEvent(new MetadataEvent.InstanceMetadataEvent(singleton, instanceInfo.getMetadataId(), false));
}
@Override
public boolean addServiceInstance(Service service, InstancePublishInfo instancePublishInfo) {
if (null == publishers.put(service, instancePublishInfo)) {
if (instancePublishInfo instanceof BatchInstancePublishInfo) {
MetricsMonitor.incrementIpCountWithBatchRegister(instancePublishInfo);
} else {
MetricsMonitor.incrementInstanceCount();
}
}
// 发布客户端变动的事件
NotifyCenter.publishEvent(new ClientEvent.ClientChangedEvent(this));
Loggers.SRV_LOG.info("Client change for service {}, {}", service, getClientId());
return true;
}
光是一个注册,就发布了好几个事件。每个事件都有自己的处理逻辑。现在假如我们没有NotifyCenter
进行解耦,而是一个个处理,那代码得多长,逻辑得多复杂,而且对于同一类型的事件的处理还会有这各种冗余的代码。而现在我们只需要关心我们感兴趣的事件去处理就好,假如以后新增了其他的逻辑,我们也可以增加新的事件,在这里进行publish
,再写上自己的订阅类处理就好。
现在我们只拿一个事件来分析,比如NotifyCenter.publishEvent(new ClientOperationEvent.ClientRegisterServiceEvent(singleton, clientId))
这个事件。拿一个事件分析是为了告诉大家如何分析,还有它的分析思路。其他的大家可以自己学着去分析。
既然我们已经明确了现在要分析ClientOperationEvent.ClientRegisterServiceEvent
事件了。那首先我们得找到事件的订阅者。因为订阅者既然订阅了事件,那说明它对事件感兴趣,要对事件做出响应的处理。对于程序代码来说,肯定就是onEvent(Event event)
的方法去处理逻辑。
我们使用IDE点击类名,查看调用,可以看到有好几处引用了。
不过仔细看就能发现,除了前面两个是处理方法外,其他的都是发布事件。而前两个都属于类ClientServiceIndexesManager
。我们就继续分析ClientServiceIndexesManager
。
在ClientServiceIndexesManager
的构造方法中可以看到其在NotifyCenter
中注册了自己。
Nacos
中订阅者一般都是在创建的时候,也就是构造方法中注册
public ClientServiceIndexesManager() {
// 注册自己
NotifyCenter.registerSubscriber(this, NamingEventPublisherFactory.getInstance());
}
然后在处理事件中,仅仅处理了两类事件,其中有一个就是ClientOperationEvent
@Override
public void onEvent(Event event) {
if (event instanceof ClientEvent.ClientDisconnectEvent) {
handleClientDisconnect((ClientEvent.ClientDisconnectEvent) event);
} else if (event instanceof ClientOperationEvent) {
handleClientOperation((ClientOperationEvent) event);
}
}
private void handleClientOperation(ClientOperationEvent event) {
Service service = event.getService();
String clientId = event.getClientId();
if (event instanceof ClientOperationEvent.ClientRegisterServiceEvent) {
// 处理ClientRegisterServiceEvent事件
addPublisherIndexes(service, clientId);
} else if (event instanceof ClientOperationEvent.ClientDeregisterServiceEvent) {
removePublisherIndexes(service, clientId);
} else if (event instanceof ClientOperationEvent.ClientSubscribeServiceEvent) {
addSubscriberIndexes(service, clientId);
} else if (event instanceof ClientOperationEvent.ClientUnsubscribeServiceEvent) {
removeSubscriberIndexes(service, clientId);
}
}
private void addPublisherIndexes(Service service, String clientId) {
publisherIndexes.computeIfAbsent(service, key -> new ConcurrentHashSet<>());
publisherIndexes.get(service).add(clientId);
// 又发布了一个服务变化事件
NotifyCenter.publishEvent(new ServiceEvent.ServiceChangedEvent(service, true));
}
不知道大家看到这一个个事件是不是有点晕,一会clientEvent
,一会又ServiceEvent
。下面我就针对代码中的各个单词对应的含义进行解释一下。解释完后,大家就会对这些概念清楚很多,也能明白作者意图。
Service
,Cluster
,Instance
,Client
的解释我们从Service
开始看。Service
包含了服务名,应用名,组名。
public class Service implements Serializable {
private static final long serialVersionUID = -3470985546826874460L;
private String name;
private float protectThreshold = 0.0F;
private String appName;
private String groupName;
private Map<String, String> metadata = new HashMap<>();
//...忽略其他方法
}
Cluster
中包含了一个serviceName
的属性。也就是Cluster
是属于了一个Service
的。
public class Cluster implements Serializable {
private static final long serialVersionUID = -7196138840047197271L;
private String serviceName;
private String name;
private AbstractHealthChecker healthChecker = new Tcp();
private int defaultPort = 80;
private int defaultCheckPort = 80;
private boolean useIPPort4Check = true;
private Map<String, String> metadata = new HashMap<>();
//...其它一些get和set方法忽略
}
Instance
中既有一个clusterName
,又有一个serviceName
。说明它是一个服务中,集群中的一个实例信息。
public class Instance implements Serializable {
private static final long serialVersionUID = -742906310567291979L;
private String instanceId;
private String ip;
private int port;
private double weight = 1.0D;
private boolean healthy = true;
private boolean enabled = true;
private boolean ephemeral = true;
private String clusterName;
private String serviceName;
private Map<String, String> metadata = new HashMap<>();
//其它一些get和set方法忽略
...
}
下面是我对服务和集群的截图。
可以看到一个服务名是可以有多个集群和多个实例的。而一个集群可能有多个实例,一个实例就是一个客户端的连接。
最后我们还有个Client
的概念。进入源码,Cient
并不是一个实体类,而是一个接口。它定义了一系列操作的接口。
public interface Client {
String getClientId();
boolean isEphemeral();
boolean addServiceInstance(Service service, InstancePublishInfo instancePublishInfo);
InstancePublishInfo removeServiceInstance(Service service);
// 其他的一些方法。。。
}
明白了这几个概念后,我们再看看和他们相关的类。比如ClientOperationEvent
,InstancesChangeEvent
,ServiceEvent
。然后再从概念出发,当一个客户端注册到服务端,可能会引发一系列的变化,比如说新服务的注册上线,新的集群的上线,新的实例的上线等。所以可以看到注册服务所触发的一系列的事件,他们实际上都是一环扣一环,紧密相连的。
本篇就分析到这里,下一篇我们从ServiceEvent.ServiceChangedEvent
继续往下分析。