补充源码证据
主章节之外的关键分支与2.5.4对照窗口。每个窗口均来自固定提交,全文未修改。
身份比较:ephemeral不在equals中
源码正文 · Nacos3.2.4 · L107–L117
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Service)) {
return false;
}
Service service = (Service) o;
return namespace.equals(service.namespace) && group.equals(service.group)
&& name.equals(service.name);
}
Distro过滤持久Client与非责任节点
源码正文 · Nacos3.2.4 · L130–L134
private boolean isInvalidClient(Client client) {
return null == client || !client.isEphemeral()
|| !clientManager.isResponsibleClient(client);
}
A2A分别发布索引与正文
源码正文 · Nacos3.2.4 · L97–L129
public void registerAgent(AgentCard agentCard, String namespaceId, String registrationType)
throws NacosException {
try {
AgentCardVersionInfo agentCardVersionInfo =
AgentCardUtil.buildAgentCardVersionInfo(agentCard,
registrationType, true);
ConfigForm configForm =
transferVersionInfoToConfigForm(agentCardVersionInfo, namespaceId);
ConfigRequestInfo versionConfigRequest = new ConfigRequestInfo();
versionConfigRequest.setUpdateForExist(Boolean.FALSE);
configOperationService.publishConfig(configForm, versionConfigRequest, null);
AgentCardDetailInfo agentCardDetailInfo =
AgentCardUtil.buildAgentCardDetailInfo(agentCard,
registrationType);
ConfigForm configFormVersion =
transferAgentInfoToConfigForm(agentCardDetailInfo, namespaceId);
ConfigRequestInfo agentCardConfigRequest = new ConfigRequestInfo();
agentCardConfigRequest.setUpdateForExist(Boolean.FALSE);
long startOperationTime = System.currentTimeMillis();
configOperationService.publishConfig(configFormVersion, agentCardConfigRequest, null);
syncEffectService.toSync(configFormVersion, startOperationTime);
AiResourceTraceService.logSuccess("a2a", agentCard.getName(), agentCard.getVersion(),
AiResourceTraceService.OP_CREATE_DRAFT, VisibilityHelper.resolveCurrentIdentity(),
VisibilityHelper.resolveClientIp());
} catch (ConfigAlreadyExistsException e) {
throw new NacosApiException(NacosException.CONFLICT, ErrorCode.RESOURCE_CONFLICT,
String.format("AgentCard name %s already exist", agentCard.getName()));
}
}
Skill从manifest定位版本与文件
源码正文 · Nacos3.2.4 · L1108–L1144
@Override
public Skill querySkill(String namespaceId, String name, String version, String label)
throws NacosException {
AiResource meta = resourceManager.findMeta(namespaceId, name, RESOURCE_TYPE_SKILL);
if (meta == null) {
throw new NacosApiException(NacosException.NOT_FOUND, ErrorCode.RESOURCE_NOT_FOUND,
"Skill not found: " + name);
}
resourceManager.ensureReadableOrNotFound(meta, "Skill not found: " + name);
SkillIndexManifest manifest = manifestService.query(namespaceId, name);
if (manifest == null || manifest.getVersions() == null
|| manifest.getVersions().isEmpty()) {
throw new NacosApiException(NacosException.NOT_FOUND, ErrorCode.RESOURCE_NOT_FOUND,
"Skill not found: " + name);
}
String resolved = SkillIndexManifestService.resolveVersion(manifest, version, label);
if (StringUtils.isBlank(resolved)) {
throw new NacosApiException(NacosException.NOT_FOUND, ErrorCode.RESOURCE_NOT_FOUND,
"Skill version not found: " + name);
}
List<String> files = manifest.getVersions().get(resolved);
if (files == null || files.isEmpty()) {
throw new NacosApiException(NacosException.NOT_FOUND, ErrorCode.RESOURCE_NOT_FOUND,
"Skill version not found: " + name + "@" + resolved);
}
Skill skill = loadSkillFromFiles(namespaceId, name, resolved, files);
NotifyCenter.publishEvent(
new SkillDownloadEvent(namespaceId, name, RESOURCE_TYPE_SKILL, resolved));
return skill;
}
gRPC业务鉴权与节点身份分支
源码正文 · Nacos3.2.4 · L68–L142
@Override
public Response filter(Request request, RequestMeta meta, Class handlerClazz)
throws NacosException {
try {
Method method = getHandleMethod(handlerClazz);
if (method.isAnnotationPresent(Secured.class)) {
Secured secured = method.getAnnotation(Secured.class);
RequestContext requestContext = RequestContextHolder.getContext();
requestContext.getAuthContext().setApiType(secured.apiType().name());
if (ApiType.INNER_API.equals(secured.apiType())
&& !innerApiAuthEnabled.isEnabled()) {
return null;
}
if (ApiType.INNER_API != secured.apiType() && !authConfig.isAuthEnabled()) {
return null;
}
if (Loggers.AUTH.isDebugEnabled()) {
Loggers.AUTH.debug("auth start, request: {}",
request.getClass().getSimpleName());
}
ServerIdentityResult identityResult =
protocolAuthService.checkServerIdentity(request, secured);
switch (identityResult.getStatus()) {
case FAIL:
Response defaultResponseInstance = getDefaultResponseInstance(handlerClazz);
defaultResponseInstance.setErrorInfo(NacosException.NO_RIGHT,
identityResult.getMessage());
return defaultResponseInstance;
case MATCHED:
return null;
default:
break;
}
if (!protocolAuthService.enableAuth(secured)) {
return null;
}
String clientIp = meta.getClientIp();
request.putHeader(Constants.Identity.X_REAL_IP, clientIp);
Resource resource = protocolAuthService.parseResource(request, secured);
IdentityContext identityContext = protocolAuthService.parseIdentity(request);
AuthResult result = protocolAuthService.validateIdentity(identityContext, resource);
requestContext.getAuthContext().setIdentityContext(identityContext);
requestContext.getAuthContext().setResource(resource);
requestContext.getAuthContext().setAuthResult(result);
if (!result.isSuccess()) {
throw new AccessException(result.format());
}
String action = secured.action().toString();
result = protocolAuthService.validateAuthority(identityContext,
new Permission(resource, action));
if (!result.isSuccess()) {
throw new AccessException(result.format());
}
}
} catch (AccessException e) {
if (Loggers.AUTH.isDebugEnabled()) {
Loggers.AUTH.debug("access denied, request: {}, reason: {}",
request.getClass().getSimpleName(),
e.getErrMsg());
}
Response defaultResponseInstance = getDefaultResponseInstance(handlerClazz);
defaultResponseInstance.setErrorInfo(NacosException.NO_RIGHT, e.getErrMsg());
return defaultResponseInstance;
} catch (Exception e) {
Response defaultResponseInstance = getDefaultResponseInstance(handlerClazz);
defaultResponseInstance.setErrorInfo(NacosException.SERVER_ERROR,
ExceptionUtil.getAllExceptionMsg(e));
return defaultResponseInstance;
}
return null;
}
配置事件转连接推送
源码正文 · Nacos3.2.4 · L87–L117
public void configDataChanged(String groupKey, String dataId, String group, String tenant) {
Set<String> listeners = configChangeListenContext.getListeners(groupKey);
if (CollectionUtils.isEmpty(listeners)) {
return;
}
int notifyClientCount = 0;
for (final String client : listeners) {
Connection connection = connectionManager.getConnection(client);
if (connection == null) {
continue;
}
boolean ifNamespaceTransfer = configChangeListenContext
.getConfigListenState(client, groupKey).isNamespaceTransfer();
if (ifNamespaceTransfer) {
tenant = null;
}
ConnectionMeta metaInfo = connection.getMetaInfo();
String clientIp = metaInfo.getClientIp();
ConfigChangeNotifyRequest notifyRequest =
ConfigChangeNotifyRequest.build(dataId, group, tenant);
RpcPushTask rpcPushRetryTask = new RpcPushTask(notifyRequest,
ConfigCommonConfig.getInstance().getMaxPushRetryTimes(), client, clientIp,
metaInfo.getAppName());
push(rpcPushRetryTask, connectionManager);
notifyClientCount++;
}
Loggers.REMOTE_PUSH.info("push [{}] clients, groupKey=[{}]", notifyClientCount, groupKey);
}
配置断连标脏与重连唤醒
源码正文 · Nacos3.2.4 · L825–L833
@Override
public void onConnected(Connection connection) {
LOGGER.info("[{}] Connected,notify listen context...",
rpcClientInner.getName());
notifyListenConfig();
LOGGER.info("[{}] Connected,notify fuzzy listen context...",
rpcClientInner.getName());
configFuzzyWatchGroupKeyHolder.notifyFuzzyWatchSync();
}
拉取正文并检查Listener MD5
源码正文 · Nacos3.2.4 · L1064–L1089
private void refreshContentAndCheck(RpcClient rpcClient, CacheData cacheData,
boolean notify) {
try {
ConfigResponse response =
this.queryConfigInner(rpcClient, cacheData.dataId, cacheData.group,
cacheData.tenant, requestTimeout, notify);
cacheData.setEncryptedDataKey(response.getEncryptedDataKey());
cacheData.setContent(response.getContent());
if (null != response.getConfigType()) {
cacheData.setType(response.getConfigType());
}
if (notify) {
LOGGER.info(
"[{}] [data-received] dataId={}, group={}, tenant={}, md5={}, type={}",
agent.getName(),
cacheData.dataId, cacheData.group, cacheData.tenant, cacheData.getMd5(),
response.getConfigType());
}
cacheData.checkListenerMd5();
} catch (Exception e) {
LOGGER.error("refresh content and check md5 fail ,dataId={},group={},tenant={} ",
cacheData.dataId,
cacheData.group, cacheData.tenant, e);
}
}
控制台默认端口
源码正文 · Nacos3.2.4 · L230–L252
### Reopen deprecated v3 APIs pending removal during a migration window. Disabled by default.
# nacos.core.api.compatibility.enabled=false
### Enabled for legacy open API compatibility provided by nacos-api-legacy-adapter
# nacos.core.api.compatibility.client.enabled=true
#--------------- Nacos Console Configurations ---------------#
#*************** Nacos Console Related Configurations ***************#
### Nacos Console Main port
nacos.console.port=8080
### Nacos Server Web context path:
nacos.console.contextPath=
### Nacos Server context path, which link to nacos server `nacos.server.contextPath`, works when deployment type is `console`
nacos.console.remote.server.context-path=/nacos
#************** Console UI Configuration ***************#
### Turn on/off the nacos console ui.
#nacos.console.ui.enabled=true
### Default console UI version: 'next' (new UI) or 'legacy' (old UI)
#nacos.console.ui.default=next
JRaft提交时的leader路由
源码正文 · Nacos3.2.4 · L342–L363
public CompletableFuture<Response> commit(final String group, final Message data,
final CompletableFuture<Response> future) {
LoggerUtils.printIfDebugEnabled(Loggers.RAFT, "data requested this time : {}", data);
final RaftGroupTuple tuple = findTupleByGroup(group);
if (tuple == null) {
future.completeExceptionally(
new IllegalArgumentException("No corresponding Raft Group found : " + group));
return future;
}
FailoverClosureImpl closure = new FailoverClosureImpl(future);
final Node node = tuple.node;
if (node.isLeader()) {
applyOperation(node, data, closure);
} else {
invokeToLeader(group, data, rpcRequestTimeoutMs, closure);
}
return future;
}
查询保存快照与删除快照分支
源码正文 · Nacos3.2.4 · L1316–L1368
ConfigResponse queryConfigInner(RpcClient rpcClient, String dataId, String group,
String tenant,
long readTimeouts, boolean notify) throws NacosException {
ConfigQueryRequest request = ConfigQueryRequest.build(dataId, group, tenant);
request.putHeader(NOTIFY_HEADER, String.valueOf(notify));
ConfigQueryResponse response =
(ConfigQueryResponse) requestProxy(rpcClient, request, readTimeouts);
ConfigResponse configResponse = new ConfigResponse();
if (response.isSuccess()) {
LocalConfigInfoProcessor.saveSnapshot(this.getName(), dataId, group, tenant,
response.getContent());
configResponse.setContent(response.getContent());
configResponse.setMd5(response.getMd5());
String configType;
if (StringUtils.isNotBlank(response.getContentType())) {
configType = response.getContentType();
} else {
configType = ConfigType.TEXT.getType();
}
configResponse.setConfigType(configType);
String encryptedDataKey = response.getEncryptedDataKey();
LocalEncryptedDataKeyProcessor.saveEncryptDataKeySnapshot(agent.getName(), dataId,
group, tenant,
encryptedDataKey);
configResponse.setEncryptedDataKey(encryptedDataKey);
return configResponse;
} else if (response.getErrorCode() == ConfigQueryResponse.CONFIG_NOT_FOUND) {
LocalConfigInfoProcessor.saveSnapshot(this.getName(), dataId, group, tenant, null);
LocalEncryptedDataKeyProcessor.saveEncryptDataKeySnapshot(agent.getName(), dataId,
group, tenant, null);
return configResponse;
} else if (response.getErrorCode() == ConfigQueryResponse.CONFIG_QUERY_CONFLICT) {
LOGGER.error(
"[{}] [sub-server-error] get server config being modified concurrently, dataId={}, group={}, "
+ "tenant={}",
this.getName(), dataId, group, tenant);
throw new NacosException(NacosException.CONFLICT,
"data being modified, dataId=" + dataId + ",group=" + group + ",tenant="
+ tenant);
} else {
LOGGER.error("[{}] [sub-server-error] dataId={}, group={}, tenant={}, code={}",
this.getName(), dataId,
group, tenant, response);
throw new NacosException(response.getErrorCode(),
"http error, code=" + response.getErrorCode() + ",msg="
+ response.getMessage() + ",dataId="
+ dataId + ",group=" + group + ",tenant=" + tenant);
}
}
强制状态重启恢复
源码正文 · Nacos3.2.4 · L136–L155
private void loadState() {
if (!Files.isRegularFile(stateFile)) {
return;
}
try {
List<String> lines = Files.readAllLines(stateFile, StandardCharsets.UTF_8);
if (lines.contains(STATE_FILE_VERSION) && lines.contains(ENFORCED_STATE)) {
enforced.set(true);
statePersisted.set(true);
Loggers.RAFT.info(
"Restored enforced JRaft authentication state from persistent marker");
} else {
Loggers.RAFT.warn("Ignored invalid JRaft authentication state file at {}",
stateFile);
}
} catch (IOException e) {
Loggers.RAFT.warn("Failed to read JRaft authentication state file at {}", stateFile,
e);
}
}
2.5.4对照 · pom.xml
源码正文 · Nacos2.5.4 · L90–L146
<properties>
<revision>2.5.4</revision>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Compiler settings properties -->
<java.version>1.8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<!-- Maven properties -->
<maven.test.skip>false</maven.test.skip>
<maven.javadoc.skip>true</maven.javadoc.skip>
<!-- Exclude all generated code -->
<sonar.exclusions>file:**/generated-sourcestest/**</sonar.exclusions>
<!-- plugin version -->
<versions-maven-plugin.version>2.2</versions-maven-plugin.version>
<dependency-mediator-maven-plugin.version>1.0.2</dependency-mediator-maven-plugin.version>
<clirr-maven-plugin.version>2.7</clirr-maven-plugin.version>
<maven-enforcer-plugin.version>3.5.0</maven-enforcer-plugin.version>
<maven-compiler-plugin.version>3.5.1</maven-compiler-plugin.version>
<maven-javadoc-plugin.version>2.10.4</maven-javadoc-plugin.version>
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
<maven-source-plugin.version>3.0.1</maven-source-plugin.version>
<maven-pmd-plugin.version>3.8</maven-pmd-plugin.version>
<apache-rat-plugin.version>0.12</apache-rat-plugin.version>
<maven-resources-plugin.version>3.0.2</maven-resources-plugin.version>
<jacoco-maven-plugin.version>0.8.7</jacoco-maven-plugin.version>
<maven-surefire-plugin.version>3.2.5</maven-surefire-plugin.version>
<findbugs-maven-plugin.version>3.0.4</findbugs-maven-plugin.version>
<sonar-maven-plugin.version>3.0.2</sonar-maven-plugin.version>
<maven-gpg-plugin.version>1.6</maven-gpg-plugin.version>
<maven-failsafe-plugin.version>3.2.5</maven-failsafe-plugin.version>
<maven-assembly-plugin.version>3.0.0</maven-assembly-plugin.version>
<maven-checkstyle-plugin.version>3.1.2</maven-checkstyle-plugin.version>
<maven-easyj-version>1.1.5</maven-easyj-version>
<!-- dependency version related to plugin -->
<extra-enforcer-rules.version>1.9.0</extra-enforcer-rules.version>
<p3c-pmd.version>1.3.0</p3c-pmd.version>
<!-- dependency version -->
<nacos.logback.adapter.version>1.1.5</nacos.logback.adapter.version>
<spring-boot-dependencies.version>2.7.18</spring-boot-dependencies.version>
<servlet-api.version>3.0</servlet-api.version>
<commons-io.version>2.14.0</commons-io.version>
<commons-collections.version>3.2.2</commons-collections.version>
<slf4j-api.version>1.7.26</slf4j-api.version>
<logback.version>1.2.13</logback.version>
<log4j.version>2.17.1</log4j.version>
<mysql-connector-java.version>8.2.0</mysql-connector-java.version>
<derby.version>10.14.2.0</derby.version>
<jjwt.version>0.11.2</jjwt.version>
<grpc-java.version>1.75.0</grpc-java.version>
<proto-google-common-protos.version>2.17.0</proto-google-common-protos.version>
<protobuf-java.version>3.25.5</protobuf-java.version>
<protoc-gen-grpc-java.version>${grpc-java.version}</protoc-gen-grpc-java.version>
<hessian.version>4.0.63</hessian.version>
2.5.4对照 · InstanceRequestHandler.java
源码正文 · Nacos2.5.4 · L73–L80
private InstanceResponse registerInstance(Service service, InstanceRequest request, RequestMeta meta)
throws NacosException {
clientOperationService.registerInstance(service, request.getInstance(), meta.getConnectionId());
NotifyCenter.publishEvent(new RegisterInstanceTraceEvent(System.currentTimeMillis(),
NamingRequestUtil.getSourceIpForGrpcRequest(meta), true, service.getNamespace(), service.getGroup(),
service.getName(), request.getInstance().getIp(), request.getInstance().getPort()));
return new InstanceResponse(NamingRemoteConstants.REGISTER_INSTANCE);
}
2.5.4对照 · DistroClientDataProcessor.java
源码正文 · Nacos2.5.4 · L115–L127
private void syncToAllServer(ClientEvent event) {
Client client = event.getClient();
if (isInvalidClient(client)) {
return;
}
if (event instanceof ClientEvent.ClientDisconnectEvent) {
DistroKey distroKey = new DistroKey(client.getClientId(), TYPE);
distroProtocol.sync(distroKey, DataOperation.DELETE);
} else if (event instanceof ClientEvent.ClientChangedEvent) {
DistroKey distroKey = new DistroKey(client.getClientId(), TYPE);
distroProtocol.sync(distroKey, DataOperation.CHANGE);
}
}