blob: c7c22df0a9f6adff2d66124cf13a1453e4998866 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.dubbo.common.config;
import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.context.ApplicationExt;
import org.apache.dubbo.common.context.LifecycleAdapter;
import org.apache.dubbo.common.extension.DisableInject;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ConfigUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.config.AbstractConfig;
import org.apache.dubbo.config.context.ConfigConfigurationAdapter;
import org.apache.dubbo.rpc.model.ScopeModel;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
public class Environment extends LifecycleAdapter implements ApplicationExt {
private static final Logger logger = LoggerFactory.getLogger(Environment.class);
public static final String NAME = "environment";
// dubbo properties in classpath
private PropertiesConfiguration propertiesConfiguration;
// java system props (-D)
private SystemConfiguration systemConfiguration;
// java system environment
private EnvironmentConfiguration environmentConfiguration;
// external config, such as config-center global/default config
private InmemoryConfiguration externalConfiguration;
// external app config, such as config-center app config
private InmemoryConfiguration appExternalConfiguration;
// local app config , such as Spring Environment/PropertySources/application.properties
private InmemoryConfiguration appConfiguration;
protected CompositeConfiguration globalConfiguration;
protected List<Map<String, String>> globalConfigurationMaps;
private CompositeConfiguration defaultDynamicGlobalConfiguration;
private DynamicConfiguration defaultDynamicConfiguration;
private String localMigrationRule;
private AtomicBoolean initialized = new AtomicBoolean(false);
private ScopeModel scopeModel;
public Environment(ScopeModel scopeModel) {
this.scopeModel = scopeModel;
}
@Override
public void initialize() throws IllegalStateException {
if (initialized.compareAndSet(false, true)) {
this.propertiesConfiguration = new PropertiesConfiguration(scopeModel);
this.systemConfiguration = new SystemConfiguration();
this.environmentConfiguration = new EnvironmentConfiguration();
this.externalConfiguration = new InmemoryConfiguration("ExternalConfig");
this.appExternalConfiguration = new InmemoryConfiguration("AppExternalConfig");
this.appConfiguration = new InmemoryConfiguration("AppConfig");
loadMigrationRule();
}
}
/**
* @deprecated MigrationRule will be removed in 3.1
*/
@Deprecated
private void loadMigrationRule() {
if (Boolean.parseBoolean(System.getProperty(CommonConstants.DUBBO_MIGRATION_FILE_ENABLE, "false"))) {
String path = System.getProperty(CommonConstants.DUBBO_MIGRATION_KEY);
if (StringUtils.isEmpty(path)) {
path = System.getenv(CommonConstants.DUBBO_MIGRATION_KEY);
if (StringUtils.isEmpty(path)) {
path = CommonConstants.DEFAULT_DUBBO_MIGRATION_FILE;
}
}
this.localMigrationRule = ConfigUtils.loadMigrationRule(scopeModel.getClassLoaders(), path);
} else {
this.localMigrationRule = null;
}
}
/**
* @deprecated only for ut
*/
@Deprecated
@DisableInject
public void setLocalMigrationRule(String localMigrationRule) {
this.localMigrationRule = localMigrationRule;
}
@DisableInject
public void setExternalConfigMap(Map<String, String> externalConfiguration) {
if (externalConfiguration != null) {
this.externalConfiguration.setProperties(externalConfiguration);
}
}
@DisableInject
public void setAppExternalConfigMap(Map<String, String> appExternalConfiguration) {
if (appExternalConfiguration != null) {
this.appExternalConfiguration.setProperties(appExternalConfiguration);
}
}
@DisableInject
public void setAppConfigMap(Map<String, String> appConfiguration) {
if (appConfiguration != null) {
this.appConfiguration.setProperties(appConfiguration);
}
}
public Map<String, String> getExternalConfigMap() {
return externalConfiguration.getProperties();
}
public Map<String, String> getAppExternalConfigMap() {
return appExternalConfiguration.getProperties();
}
public Map<String, String> getAppConfigMap() {
return appConfiguration.getProperties();
}
public void updateExternalConfigMap(Map<String, String> externalMap) {
this.externalConfiguration.addProperties(externalMap);
}
public void updateAppExternalConfigMap(Map<String, String> externalMap) {
this.appExternalConfiguration.addProperties(externalMap);
}
/**
* Merge target map properties into app configuration
* @param map
*/
public void updateAppConfigMap(Map<String, String> map) {
this.appConfiguration.addProperties(map);
}
/**
* At start-up, Dubbo is driven by various configuration, such as Application, Registry, Protocol, etc.
* All configurations will be converged into a data bus - URL, and then drive the subsequent process.
* <p>
* At present, there are many configuration sources, including AbstractConfig (API, XML, annotation), - D, config center, etc.
* This methood helps us t filter out the most priority values from various configuration sources.
*
* @param config
* @param prefix
* @return
*/
public Configuration getPrefixedConfiguration(AbstractConfig config, String prefix) {
// The sequence would be: SystemConfiguration -> EnvironmentConfiguration -> AppExternalConfiguration -> ExternalConfiguration -> AppConfiguration -> AbstractConfig -> PropertiesConfiguration
Configuration instanceConfiguration = new ConfigConfigurationAdapter(config, prefix);
CompositeConfiguration compositeConfiguration = new CompositeConfiguration();
compositeConfiguration.addConfiguration(systemConfiguration);
compositeConfiguration.addConfiguration(environmentConfiguration);
compositeConfiguration.addConfiguration(appExternalConfiguration);
compositeConfiguration.addConfiguration(externalConfiguration);
compositeConfiguration.addConfiguration(appConfiguration);
compositeConfiguration.addConfiguration(instanceConfiguration);
compositeConfiguration.addConfiguration(propertiesConfiguration);
return new PrefixedConfiguration(compositeConfiguration, prefix);
}
/**
* There are two ways to get configuration during exposure / reference or at runtime:
* 1. URL, The value in the URL is relatively fixed. we can get value directly.
* 2. The configuration exposed in this method is convenient for us to query the latest values from multiple
* prioritized sources, it also guarantees that configs changed dynamically can take effect on the fly.
*/
public CompositeConfiguration getConfiguration() {
if (globalConfiguration == null) {
CompositeConfiguration configuration = new CompositeConfiguration();
configuration.addConfiguration(systemConfiguration);
configuration.addConfiguration(environmentConfiguration);
configuration.addConfiguration(appExternalConfiguration);
configuration.addConfiguration(externalConfiguration);
configuration.addConfiguration(appConfiguration);
configuration.addConfiguration(propertiesConfiguration);
globalConfiguration = configuration;
}
return globalConfiguration;
}
/**
* Get configuration map list for target instance
* @param config
* @param prefix
* @return
*/
public List<Map<String, String>> getConfigurationMaps(AbstractConfig config, String prefix) {
// The sequence would be: SystemConfiguration -> EnvironmentConfiguration -> AppExternalConfiguration -> ExternalConfiguration -> AppConfiguration -> AbstractConfig -> PropertiesConfiguration
List<Map<String, String>> maps = new ArrayList<>();
maps.add(systemConfiguration.getProperties());
maps.add(environmentConfiguration.getProperties());
maps.add(appExternalConfiguration.getProperties());
maps.add(externalConfiguration.getProperties());
maps.add(appConfiguration.getProperties());
if (config != null) {
ConfigConfigurationAdapter configurationAdapter = new ConfigConfigurationAdapter(config, prefix);
maps.add(configurationAdapter.getProperties());
}
maps.add(propertiesConfiguration.getProperties());
return maps;
}
/**
* Get global configuration as map list
* @return
*/
public List<Map<String, String>> getConfigurationMaps() {
if (globalConfigurationMaps == null) {
globalConfigurationMaps = getConfigurationMaps(null, null);
}
return globalConfigurationMaps;
}
@Override
public void destroy() throws IllegalStateException {
initialized.set(false);
systemConfiguration = null;
propertiesConfiguration = null;
environmentConfiguration = null;
externalConfiguration = null;
appExternalConfiguration = null;
appConfiguration = null;
globalConfiguration = null;
globalConfigurationMaps = null;
defaultDynamicGlobalConfiguration = null;
if (defaultDynamicConfiguration != null) {
try {
defaultDynamicConfiguration.close();
} catch (Exception e) {
logger.warn("close dynamic configuration failed: " + e.getMessage(), e);
}
defaultDynamicConfiguration = null;
}
}
/**
* Reset environment.
* For test only.
*/
public void reset() {
destroy();
initialize();
}
public String resolvePlaceholders(String str) {
return ConfigUtils.replaceProperty(str, getConfiguration());
}
public PropertiesConfiguration getPropertiesConfiguration() {
return propertiesConfiguration;
}
public SystemConfiguration getSystemConfiguration() {
return systemConfiguration;
}
public EnvironmentConfiguration getEnvironmentConfiguration() {
return environmentConfiguration;
}
public InmemoryConfiguration getExternalConfiguration() {
return externalConfiguration;
}
public InmemoryConfiguration getAppExternalConfiguration() {
return appExternalConfiguration;
}
public InmemoryConfiguration getAppConfiguration() {
return appConfiguration;
}
public String getLocalMigrationRule() {
return localMigrationRule;
}
public void refreshClassLoaders() {
propertiesConfiguration.refresh();
loadMigrationRule();
this.globalConfiguration = null;
this.globalConfigurationMaps = null;
this.defaultDynamicGlobalConfiguration = null;
}
public Configuration getDynamicGlobalConfiguration() {
if (defaultDynamicGlobalConfiguration == null) {
if (defaultDynamicConfiguration == null) {
if (logger.isWarnEnabled()) {
logger.warn("dynamicConfiguration is null , return globalConfiguration.");
}
return getConfiguration();
}
defaultDynamicGlobalConfiguration = new CompositeConfiguration();
defaultDynamicGlobalConfiguration.addConfiguration(defaultDynamicConfiguration);
defaultDynamicGlobalConfiguration.addConfiguration(getConfiguration());
}
return defaultDynamicGlobalConfiguration;
}
public Optional<DynamicConfiguration> getDynamicConfiguration() {
return Optional.ofNullable(defaultDynamicConfiguration);
}
@DisableInject
public void setDynamicConfiguration(DynamicConfiguration defaultDynamicConfiguration) {
this.defaultDynamicConfiguration = defaultDynamicConfiguration;
}
}