Skip to content

Commit

Permalink
nacos动态配置核心-配置服务类、配置订阅类
Browse files Browse the repository at this point in the history
  • Loading branch information
TangLeDaily committed Aug 30, 2023
1 parent a023e50 commit ccc3800
Show file tree
Hide file tree
Showing 5 changed files with 783 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.huaweicloud.sermant.core.service.dynamicconfig.DynamicConfigService;
import com.huaweicloud.sermant.core.service.dynamicconfig.common.DynamicConfigListener;
import com.huaweicloud.sermant.implement.service.dynamicconfig.kie.KieDynamicConfigService;
import com.huaweicloud.sermant.implement.service.dynamicconfig.nacos.NacosDynamicConfigService;
import com.huaweicloud.sermant.implement.service.dynamicconfig.zookeeper.ZooKeeperDynamicConfigService;

import java.util.List;
Expand Down Expand Up @@ -46,6 +47,9 @@ public BufferedDynamicConfigService() {
case KIE:
service = new KieDynamicConfigService();
break;
case NACOS:
service = new NacosDynamicConfigService();
break;
default:
service = new ZooKeeperDynamicConfigService();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/*
* Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.huaweicloud.sermant.implement.service.dynamicconfig.nacos;

import com.huaweicloud.sermant.core.common.LoggerFactory;
import com.huaweicloud.sermant.core.config.ConfigManager;
import com.huaweicloud.sermant.core.plugin.config.ServiceMeta;
import com.huaweicloud.sermant.core.plugin.subscribe.ConfigSubscriber;
import com.huaweicloud.sermant.core.service.ServiceManager;
import com.huaweicloud.sermant.core.service.dynamicconfig.common.DynamicConfigListener;
import com.huaweicloud.sermant.core.utils.MapUtils;
import com.huaweicloud.sermant.core.utils.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* nacos动态配置订阅类
*
* @author tangle
* @since 2023-08-22
*/
public class DynamicConfigSubscribe implements ConfigSubscriber {
private static final ServiceMeta SERVICE_META = ConfigManager.getConfig(ServiceMeta.class);

private static final Logger LOGGER = LoggerFactory.getLogger();

private final List<String> listenerCache = new ArrayList<>();

private String serviceName;

private DynamicConfigListener listener;

private String pluginName;

private String key;

private NacosDynamicConfigService nacosDynamicConfigService;

/**
* 构造函数,初始化信息及编译正则表达式
*
* @param serviceName 服务名称
* @param listener 动态配置监听器
* @param pluginName 插件名称
* @param key 配置名称
*/
public DynamicConfigSubscribe(String serviceName, DynamicConfigListener listener, String pluginName, String key) {
this.serviceName = serviceName;
this.listener = listener;
this.pluginName = pluginName;
this.key = key;
try {
this.nacosDynamicConfigService = ServiceManager.getService(NacosDynamicConfigService.class);
} catch (IllegalArgumentException e) {
LOGGER.log(Level.SEVERE, "nacosDynamicConfigService is not enabled!");
this.nacosDynamicConfigService = null;
}
}

/**
* 订阅多个group的监听
*
* @return 是否订阅成功
*/
@Override
public boolean subscribe() {
buildGroupSubscribers();
boolean result = true;
for (String group : listenerCache) {
result &= nacosDynamicConfigService.doAddConfigListener(key, group, listener);
}
return result;
}

/**
* 取消订阅多个group的监听
*
* @return 是否取消订阅成功
*/
public boolean unSubscribe() {
buildGroupSubscribers();
boolean result = true;
for (String group : listenerCache) {
result &= nacosDynamicConfigService.doRemoveConfigListener(key, group);
}
return result;
}

private void buildGroupSubscribers() {
buildAppRequest();
buildServiceRequest();
buildCustomRequest();
}

private void buildAppRequest() {
final HashMap<String, String> map = new HashMap<>();
map.put("app", SERVICE_META.getApplication());
map.put("environment", SERVICE_META.getEnvironment());
final String labelGroup = createLabelGroup(map);
listenerCache.add(labelGroup);
}

private void buildServiceRequest() {
final HashMap<String, String> map = new HashMap<>();
map.put("app", SERVICE_META.getApplication());
map.put("service", serviceName);
map.put("environment", SERVICE_META.getEnvironment());
final String labelGroup = createLabelGroup(map);
listenerCache.add(labelGroup);
}

private void buildCustomRequest() {
if (StringUtils.isBlank(SERVICE_META.getCustomLabel()) || StringUtils.isBlank(
SERVICE_META.getCustomLabelValue())) {
return;
}
final HashMap<String, String> map = new HashMap<>();
map.put(SERVICE_META.getCustomLabel(), SERVICE_META.getCustomLabelValue());
final String labelGroup = createLabelGroup(map);
listenerCache.add(labelGroup);
}

/**
* 创建标签组
*
* @param labels 标签组
* @return labelGroup 例如: app:sc_service:helloService
*/
public static String createLabelGroup(Map<String, String> labels) {
if (MapUtils.isEmpty(labels)) {
return StringUtils.EMPTY;
}
final StringBuilder group = new StringBuilder();
final List<String> keys = new ArrayList<>(labels.keySet());

// 防止相同map因排序不同而导致最后的label不一致
Collections.sort(keys);
for (String key : keys) {
String value = labels.get(key);
if (key == null || value == null) {
LOGGER.log(Level.SEVERE, "Invalid group label, key: {0}, value: {1}", new String[]{key, value});
continue;
}
group.append(key).append(":").append(value).append("_");
}
if (group.length() == 0) {
return StringUtils.EMPTY;
}
if (!NacosUtils.isValidGroupName(group.toString())) {
LOGGER.log(Level.SEVERE, "Invalid group name. group: {0}", group);
return StringUtils.EMPTY;
}
return NacosUtils.reBuildGroup(group.deleteCharAt(group.length() - 1).toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.alibaba.nacos.api.exception.NacosException;

import java.io.Closeable;
import java.util.Optional;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand Down Expand Up @@ -193,10 +194,14 @@ private Properties createProperties(String connectString, int sessionTimeout, St
private Properties createProperties(String connectString, int sessionTimeout, String namespace, String userName,
String password) {
Properties properties = this.createProperties(connectString, sessionTimeout, namespace);
properties.setProperty(PropertyKeyConst.USERNAME,
String.valueOf(AesUtil.decrypt(CONFIG.getPrivateKey(), userName)));
properties.setProperty(PropertyKeyConst.PASSWORD,
String.valueOf(AesUtil.decrypt(CONFIG.getPrivateKey(), password)));
Optional<String> userNameOptinal = AesUtil.decrypt(CONFIG.getPrivateKey(), userName);
Optional<String> passWordOptinal = AesUtil.decrypt(CONFIG.getPrivateKey(), password);
if (!userNameOptinal.isPresent() || !passWordOptinal.isPresent()) {
LOGGER.log(Level.SEVERE, "Nacos username and password parsing failed");
return properties;
}
properties.setProperty(PropertyKeyConst.USERNAME, userNameOptinal.get());
properties.setProperty(PropertyKeyConst.PASSWORD, passWordOptinal.get());
return properties;
}

Expand Down Expand Up @@ -229,7 +234,11 @@ private void createConfigService(String connectString, Properties properties) {
private boolean connect(Properties properties) throws NacosException {
int tryNum = 0;
while (tryNum++ <= CONFIG.getConnectRetryTimes()) {
// nacos的客户端初始化时候会获取当前线程的类加载器,此处需要更改,并且随后改回原本类加载器
ClassLoader tempClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
configService = NacosFactory.createConfigService(properties);
Thread.currentThread().setContextClassLoader(tempClassLoader);
if (KEY_CONNECTED.equals(configService.getServerStatus())) {
return true;
}
Expand Down
Loading

0 comments on commit ccc3800

Please sign in to comment.