com.alibaba.cloud.nacos.configdata.NacosConfigDataLocationResolver Maven / Gradle / Ivy
/*
* Copyright 2013-2023 the original author or authors.
*
* 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
*
* https://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.alibaba.cloud.nacos.configdata;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.alibaba.cloud.nacos.NacosConfigProperties;
import com.huaweicloud.nacos.config.manager.NacosConfigServiceMasterManager;
import com.huaweicloud.nacos.config.manager.NacosConfigServiceStandbyManager;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.springframework.boot.BootstrapRegistry.InstanceSupplier;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.context.config.ConfigDataLocation;
import org.springframework.boot.context.config.ConfigDataLocationNotFoundException;
import org.springframework.boot.context.config.ConfigDataLocationResolver;
import org.springframework.boot.context.config.ConfigDataLocationResolverContext;
import org.springframework.boot.context.config.ConfigDataResource;
import org.springframework.boot.context.config.ConfigDataResourceNotFoundException;
import org.springframework.boot.context.config.Profiles;
import org.springframework.boot.context.properties.bind.BindHandler;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.core.Ordered;
import static com.alibaba.cloud.nacos.configdata.NacosConfigDataResource.NacosItemConfig;
/**
* Forked from com.alibaba.cloud.nacos.configdata.NacosConfigDataLocationResolver.java
*
* Implementation of {@link ConfigDataLocationResolver}, load Nacos
* {@link ConfigDataResource}.
*
* @author freeman
* @since 2021.0.1.0
*/
public class NacosConfigDataLocationResolver
implements ConfigDataLocationResolver, Ordered {
/**
* Prefix for Config Server imports.
*/
public static final String PREFIX = "nacos:";
private final Log log;
// support params
private static final String GROUP = "group";
private static final String REFRESH_ENABLED = "refreshEnabled";
private static final String PREFERENCE = "preference";
public NacosConfigDataLocationResolver(DeferredLogFactory logFactory) {
this.log = logFactory.getLog(getClass());
}
@Override
public int getOrder() {
return -1;
}
protected NacosConfigProperties loadProperties(
ConfigDataLocationResolverContext context) {
Binder binder = context.getBinder();
BindHandler bindHandler = getBindHandler(context);
NacosConfigProperties nacosConfigProperties;
if (context.getBootstrapContext().isRegistered(NacosConfigProperties.class)) {
nacosConfigProperties = context.getBootstrapContext()
.get(NacosConfigProperties.class);
} else {
nacosConfigProperties = binder
.bind("spring.cloud.nacos", Bindable.of(NacosConfigProperties.class),
bindHandler)
.map(properties -> binder
.bind(NacosConfigProperties.PREFIX,
Bindable.ofInstance(properties), bindHandler)
.orElse(properties))
.orElseGet(() -> binder
.bind(NacosConfigProperties.PREFIX,
Bindable.of(NacosConfigProperties.class), bindHandler)
.orElseGet(NacosConfigProperties::new));
}
return nacosConfigProperties;
}
private BindHandler getBindHandler(ConfigDataLocationResolverContext context) {
return context.getBootstrapContext().getOrElse(BindHandler.class, null);
}
protected Log getLog() {
return this.log;
}
@Override
public boolean isResolvable(ConfigDataLocationResolverContext context,
ConfigDataLocation location) {
if (!location.hasPrefix(getPrefix())) {
return false;
}
return context.getBinder()
.bind(NacosConfigProperties.PREFIX + ".enabled", Boolean.class)
.orElse(true);
}
protected String getPrefix() {
return PREFIX;
}
@Override
public List resolve(
ConfigDataLocationResolverContext context, ConfigDataLocation location)
throws ConfigDataLocationNotFoundException,
ConfigDataResourceNotFoundException {
return Collections.emptyList();
}
@Override
public List resolveProfileSpecific(
ConfigDataLocationResolverContext resolverContext,
ConfigDataLocation location, Profiles profiles)
throws ConfigDataLocationNotFoundException {
NacosConfigProperties properties = loadProperties(resolverContext);
ConfigurableBootstrapContext bootstrapContext = resolverContext
.getBootstrapContext();
bootstrapContext.registerIfAbsent(NacosConfigProperties.class,
InstanceSupplier.of(properties));
registerConfigManager(properties, bootstrapContext);
return loadConfigDataResources(location, profiles, properties);
}
private List loadConfigDataResources(
ConfigDataLocation location, Profiles profiles,
NacosConfigProperties properties) {
List result = new ArrayList<>();
URI uri = getUri(location, properties);
if (StringUtils.isBlank(dataIdFor(uri))) {
throw new IllegalArgumentException("dataId must be specified");
}
NacosConfigDataResource resource = new NacosConfigDataResource(properties,
location.isOptional(), profiles, log,
new NacosItemConfig().setGroup(groupFor(uri, properties))
.setDataId(dataIdFor(uri)).setSuffix(suffixFor(uri, properties))
.setRefreshEnabled(refreshEnabledFor(uri, properties))
.setPreference(preferenceFor(uri)));
result.add(resource);
return result;
}
private String preferenceFor(URI uri) {
return getQueryMap(uri).get(PREFERENCE);
}
private URI getUri(ConfigDataLocation location, NacosConfigProperties properties) {
String path = location.getNonPrefixedValue(getPrefix());
if (StringUtils.isBlank(path)) {
path = "/";
}
if (!path.startsWith("/")) {
path = "/" + path;
}
String uri = properties.getServerAddr() + path;
return getUri(uri);
}
private void registerConfigManager(NacosConfigProperties properties,
ConfigurableBootstrapContext bootstrapContext) {
if (!bootstrapContext.isRegistered(NacosConfigServiceMasterManager.class)) {
bootstrapContext.register(NacosConfigServiceMasterManager.class,
InstanceSupplier.of(new NacosConfigServiceMasterManager(properties)));
}
if (!bootstrapContext.isRegistered(NacosConfigServiceStandbyManager.class)) {
bootstrapContext.register(NacosConfigServiceStandbyManager.class,
InstanceSupplier.of(new NacosConfigServiceStandbyManager(properties)));
}
}
private URI getUri(String uris) {
String realUri = uris;
if (!realUri.startsWith("http://") && !realUri.startsWith("https://")) {
realUri = "http://" + realUri;
}
URI uri;
try {
uri = new URI(realUri);
} catch (URISyntaxException e) {
throw new IllegalArgumentException("illegal URI: " + realUri, e);
}
return uri;
}
private String groupFor(URI uri, NacosConfigProperties properties) {
Map queryMap = getQueryMap(uri);
return queryMap.containsKey(GROUP) ? queryMap.get(GROUP) : properties.getGroup();
}
private Map getQueryMap(URI uri) {
String query = uri.getQuery();
if (StringUtils.isBlank(query)) {
return Collections.emptyMap();
}
Map result = new HashMap<>(4);
for (String entry : query.split("&")) {
String[] kv = entry.split("=");
if (kv.length == 2) {
result.put(kv[0], kv[1]);
}
}
return result;
}
private String suffixFor(URI uri, NacosConfigProperties properties) {
String dataId = dataIdFor(uri);
if (dataId != null && dataId.contains(".")) {
return dataId.substring(dataId.lastIndexOf('.') + 1);
}
return properties.getFileExtension();
}
private boolean refreshEnabledFor(URI uri, NacosConfigProperties properties) {
Map queryMap = getQueryMap(uri);
return queryMap.containsKey(REFRESH_ENABLED)
? Boolean.parseBoolean(queryMap.get(REFRESH_ENABLED))
: properties.isRefreshEnabled();
}
private String dataIdFor(URI uri) {
String path = uri.getPath();
// notice '/'
if (path == null || path.length() <= 1) {
return StringUtils.EMPTY;
}
String[] parts = path.substring(1).split("/");
if (parts.length != 1) {
throw new IllegalArgumentException("illegal dataId");
}
return parts[0];
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy