# 第5节.Nacos中委派设计模式的使用

# 一、委派设计模式概念

委派就像是拿另一种方法替代了原本的方法,交给现在这个替代后的方法使用,使用时和原来的方法没有区别。

允许对象组合实现与继承相同的代码重用。它的基本作用就是负责任务的调用和分配任务,是一种特殊的静态代理,可以理解我全权代理,但是代码模式注重过程,而委派模式注重结果。属于行为型模式。

# 二、委派设计模式角色

  1. 抽象任务角色(Task):定义一个接口,它有若干实现类。
  2. 委派角色(Delegate):负责在各个具体角色实例之间做出决策,屏判断调用具体实现的方法。
  3. 具体任务角色(Concrete)真正执行任务的角色

通常我们看到某个类的名称中包含Delegete字符串,基本上都是一种委派设计模式的体现。类关系如下:

client

调用

Delegate类----------实现-----------任务角色接口

具体任务角色1----------实现-----------任务角色接口

具体任务角色2----------实现-----------任务角色接口

# 三、Nacos中委派模式的使用

# 1、客户端模块的请求委派处理

以客户端的请求入口NacosNamingService类为起点,在该类的构造函数中对接口NamingClientProxy进行了委派的初始化,代码如下:

this.clientProxy = new NamingClientProxyDelegate(this.namespace, serviceInfoHolder, properties, changeNotifier);

所以角色对应关系如下:

角色名称 对应接口/类
抽象任务角色 NamingClientProxy
委派角色 NamingClientProxyDelegate
具体任务角色 NamingHttpClientProxy、NamingGrpcClientProxy

可以了解到NacosNamingService中的客户端请求的业务逻辑设计为委派模式,去根据自己的业务去控制什么时候采用HTTP请求,什么时候采用GRPC请求。

在Nacos2.1版本中:

对于客户端注册服务方法registerService和取消注册服务方法deregisterService的逻辑,采用动态判断,当实例为临时的方式的时候,使用grpcClientProxy,非临时采用httpClientProxy。

private NamingClientProxy getExecuteClientProxy(Instance instance) {
    return instance.isEphemeral() ? grpcClientProxy : httpClientProxy;
}

对于获得服务列表的方法,采用的grpcClientProxy的方式:

@Override
public ListView<String> getServiceList(int pageNo, int pageSize, String groupName, AbstractSelector selector)
        throws NacosException {
    return grpcClientProxy.getServiceList(pageNo, pageSize, groupName, selector);
}

对于订阅subscribe和取消订阅的方法,采用的也是grpcClientProxy的方式。

# 2、服务端模块的客户端管理器委派处理

以服务端的接收心跳HealthController类为起点,在该类的会判断当前服务器是否支持GRPC的特征,如果是则使用Nacos2中的HealthOperatorV2Impl类进行心跳操作的相关处理,而这个类中需要注入一个ClientManager客户管理期委托实现。

public HealthOperatorV2Impl(NamingMetadataManager metadataManager, ClientManagerDelegate clientManager,
        ClientOperationServiceProxy clientOperationService) {
    this.metadataManager = metadataManager;
    this.clientManager = clientManager;
    this.clientOperationService = clientOperationService;
}

所以角色对应关系如下:

角色名称 对应接口/类
抽象任务角色 ClientManager
委派角色 ClientManagerDelegate
具体任务角色 ConnectionBasedClientManager、EphemeralIpPortClientManager、PersistentIpPortClientManager

通过判断客户端的ID信息,委派不同的任务角色进行处理,核心判断逻辑如下:

private ClientManager getClientManagerById(String clientId) {
    if (isConnectionBasedClient(clientId)) {
        return connectionBasedClientManager;
    }
    return clientId.endsWith(ClientConstants.PERSISTENT_SUFFIX) ? persistentIpPortClientManager : ephemeralIpPortClientManager;
}

private boolean isConnectionBasedClient(String clientId) {
    return !clientId.contains(IpPortBasedClient.ID_DELIMITER);
}

# 3、服务端模块的一致性协议委派处理

Nacos服务端在处理服务一致性协议相关的时候,也采委派模式去选择Distro协议处理业务还是Raft协议处理业务,代码注入如下:

@Resource(name = "consistencyDelegate")
private ConsistencyService consistencyService;

所以角色对应关系如下:

角色名称 对应接口/类
抽象任务角色 ConsistencyService
委派角色 DelegateConsistencyServiceImpl
具体任务角色 PersistentConsistencyServiceDelegateImpl、EphemeralConsistencyService

可以看到针对持久化协议的设计,本身又是一个内部委派处理方式,代码如下:

@DependsOn("ProtocolManager")
@Service("consistencyDelegate")
public class DelegateConsistencyServiceImpl implements ConsistencyService {
    
    private final PersistentConsistencyServiceDelegateImpl persistentConsistencyService;
    
    private final EphemeralConsistencyService ephemeralConsistencyService;
    
    public DelegateConsistencyServiceImpl(PersistentConsistencyServiceDelegateImpl persistentConsistencyService,
            EphemeralConsistencyService ephemeralConsistencyService) {
        this.persistentConsistencyService = persistentConsistencyService;
        this.ephemeralConsistencyService = ephemeralConsistencyService;
    }
 		
  	@Override
    public void put(String key, Record value) throws NacosException {
        mapConsistencyService(key).put(key, value);
    }
  	
  	/**
  	* 委派同时满足
  	*/
  	@Override
    public boolean isAvailable() {
        return ephemeralConsistencyService.isAvailable() && persistentConsistencyService.isAvailable();
    }
  
  	/**
  	* 委派判断条件
  	*/
  	private ConsistencyService mapConsistencyService(String key) {
        return KeyBuilder.matchEphemeralKey(key) ? ephemeralConsistencyService : persistentConsistencyService;
    }
  
}

在Nacos2.1中,针对持久化协议的委派处理,PersistentConsistencyServiceDelegateImpl,相关角色对应关系如下:

角色名称 对应接口/类
抽象任务角色 PersistentConsistencyService
委派角色 PersistentConsistencyServiceDelegateImpl
具体任务角色 RaftConsistencyServiceImpl、BasePersistentServiceProcessor

判断规则如下:

private PersistentConsistencyService switchOne() {
    return switchNewPersistentService ? newPersistentConsistencyService : oldPersistentConsistencyService;
}

在Nacos中类似使用委派模式的地方还有很多,可以看到通过该模式,让我们对于任务的分配和委派很清晰。对于我们业务开发其实也是有帮助的,日常业务开发中,多思考下企业对于一些兼容类型的处理或扩展类型的处理都可以用到该模式去处理。

Last Updated: 10/3/2022, 5:50:00 PM