@ -17,12 +17,24 @@
package com.tencent.cloud.polaris.config.adapter ;
import java.util.ArrayList ;
import java.util.Arrays ;
import java.util.LinkedList ;
import java.util.List ;
import java.util.Map ;
import java.util.concurrent.ConcurrentHashMap ;
import com.tencent.cloud.polaris.config.config.ConfigFileGroup ;
import com.tencent.cloud.polaris.config.config.PolarisConfigProperties ;
import com.tencent.cloud.polaris.config.enums.ConfigFileFormat ;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties ;
import com.tencent.polaris.configuration.api.core.ConfigFileMetadata ;
import com.tencent.polaris.configuration.api.core.ConfigFileService ;
import com.tencent.polaris.configuration.api.core.ConfigKVFile ;
import com.tencent.polaris.configuration.client.internal.DefaultConfigFileMetadata ;
import org.apache.commons.lang.ArrayUtils ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
import org.springframework.cloud.bootstrap.config.PropertySourceLocator ;
import org.springframework.core.annotation.Order ;
@ -30,6 +42,7 @@ import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.Environment ;
import org.springframework.core.env.PropertySource ;
import org.springframework.util.CollectionUtils ;
import org.springframework.util.StringUtils ;
/ * *
* Spring cloud reserved core configuration loading SPI .
@ -41,38 +54,185 @@ import org.springframework.util.CollectionUtils;
@Order ( 0 )
public class PolarisConfigFileLocator implements PropertySourceLocator {
private static final Logger LOGGER = LoggerFactory . getLogger ( PolarisConfigFileLocator . class ) ;
private static final String POLARIS_CONFIG_PROPERTY_SOURCE_NAME = "polaris-config" ;
private final PolarisConfigProperties polarisConfigProperties ;
private final PolarisConfigFilePuller polarisConfigFilePuller ;
private final PolarisContextProperties polarisContextProperties ;
private final ConfigFileService configFileService ;
private final PolarisPropertySourceManager polarisPropertySourceManager ;
private final Environment environment ;
// this class provides customized logic for some customers to configure special business group files
private final PolarisConfigCustomExtensionLayer polarisConfigCustomExtensionLayer = PolarisServiceLoaderUtil . getPolarisConfigCustomExtensionLayer ( ) ;
public PolarisConfigFileLocator ( PolarisConfigProperties polarisConfigProperties ,
PolarisContextProperties polarisContextProperties , ConfigFileService configFileService ,
PolarisPropertySourceManager polarisPropertySourceManager , Environment environment ) {
public PolarisConfigFileLocator ( PolarisConfigProperties polarisConfigProperties , PolarisContextProperties polarisContextProperties , ConfigFileService configFileService , PolarisPropertySourceManager polarisPropertySourceManager , Environment environment ) {
this . polarisConfigProperties = polarisConfigProperties ;
this . polarisConfigFilePuller = PolarisConfigFilePuller . get ( polarisContextProperties , configFileService ,
polarisPropertySourceManager ) ;
this . polarisContextProperties = polarisContextProperties ;
this . configFileService = configFileService ;
this . polarisPropertySourceManager = polarisPropertySourceManager ;
this . environment = environment ;
}
@Override
public PropertySource < ? > locate ( Environment environment ) {
CompositePropertySource compositePropertySource = new CompositePropertySource (
POLARIS_CONFIG_PROPERTY_SOURCE_NAME ) ;
CompositePropertySource compositePropertySource = new CompositePropertySource ( POLARIS_CONFIG_PROPERTY_SOURCE_NAME ) ;
try {
// load custom config extension files
initCustomPolarisConfigExtensionFiles ( compositePropertySource ) ;
// load spring boot default config files
initInternalConfigFiles ( compositePropertySource ) ;
// load custom config files
List < ConfigFileGroup > configFileGroups = polarisConfigProperties . getGroups ( ) ;
if ( CollectionUtils . isEmpty ( configFileGroups ) ) {
return compositePropertySource ;
}
initCustomPolarisConfigFiles ( compositePropertySource , configFileGroups ) ;
return compositePropertySource ;
}
finally {
afterLocatePolarisConfigExtension ( compositePropertySource ) ;
}
}
private void initCustomPolarisConfigExtensionFiles ( CompositePropertySource compositePropertySource ) {
if ( polarisConfigCustomExtensionLayer = = null ) {
LOGGER . debug ( "[SCT Config] PolarisAdaptorTsfConfigExtensionLayer is not init, ignore the following execution steps" ) ;
return ;
}
polarisConfigCustomExtensionLayer . initConfigFiles ( environment , compositePropertySource , polarisPropertySourceManager , configFileService ) ;
}
private void afterLocatePolarisConfigExtension ( CompositePropertySource compositePropertySource ) {
if ( polarisConfigCustomExtensionLayer = = null ) {
LOGGER . debug ( "[SCT Config] PolarisAdaptorTsfConfigExtensionLayer is not init, ignore the following execution steps" ) ;
return ;
}
polarisConfigCustomExtensionLayer . executeAfterLocateConfigReturning ( compositePropertySource ) ;
}
private void initInternalConfigFiles ( CompositePropertySource compositePropertySource ) {
List < ConfigFileMetadata > internalConfigFiles = getInternalConfigFiles ( ) ;
for ( ConfigFileMetadata configFile : internalConfigFiles ) {
PolarisPropertySource polarisPropertySource = loadPolarisPropertySource ( configFile . getNamespace ( ) , configFile . getFileGroup ( ) , configFile . getFileName ( ) ) ;
compositePropertySource . addPropertySource ( polarisPropertySource ) ;
// load spring boot default config files
polarisPropertySourceManager . addPropertySource ( polarisPropertySource ) ;
LOGGER . info ( "[SCT Config] Load and inject polaris config file. file = {}" , configFile ) ;
}
}
private List < ConfigFileMetadata > getInternalConfigFiles ( ) {
String namespace = polarisContextProperties . getNamespace ( ) ;
String serviceName = polarisContextProperties . getService ( ) ;
if ( ! StringUtils . hasText ( serviceName ) ) {
serviceName = environment . getProperty ( "spring.application.name" ) ;
}
List < ConfigFileMetadata > internalConfigFiles = new LinkedList < > ( ) ;
// priority: application-${profile} > application > boostrap-${profile} > boostrap
String [ ] activeProfiles = environment . getActiveProfiles ( ) ;
String [ ] defaultProfiles = environment . getDefaultProfiles ( ) ;
String serviceName = environment . getProperty ( "spring.application.name" ) ;
polarisConfigFilePuller . initInternalConfigFiles (
compositePropertySource , activeProfiles , defaultProfiles , serviceName ) ;
List < String > profileList = new ArrayList < > ( ) ;
if ( ArrayUtils . isNotEmpty ( activeProfiles ) ) {
profileList . addAll ( Arrays . asList ( activeProfiles ) ) ;
}
else if ( ArrayUtils . isNotEmpty ( defaultProfiles ) ) {
profileList . addAll ( Arrays . asList ( defaultProfiles ) ) ;
}
// build application config files
buildInternalApplicationConfigFiles ( internalConfigFiles , namespace , serviceName , profileList ) ;
// build bootstrap config files
buildInternalBootstrapConfigFiles ( internalConfigFiles , namespace , serviceName , profileList ) ;
// load custom config files
List < ConfigFileGroup > configFileGroups = polarisConfigProperties . getGroups ( ) ;
if ( CollectionUtils . isEmpty ( configFileGroups ) ) {
return compositePropertySource ;
return internalConfigFiles ;
}
private void buildInternalApplicationConfigFiles ( List < ConfigFileMetadata > internalConfigFiles , String namespace , String serviceName , List < String > profileList ) {
for ( String profile : profileList ) {
if ( ! StringUtils . hasText ( profile ) ) {
continue ;
}
internalConfigFiles . add ( new DefaultConfigFileMetadata ( namespace , serviceName , "application-" + profile + ".properties" ) ) ;
internalConfigFiles . add ( new DefaultConfigFileMetadata ( namespace , serviceName , "application-" + profile + ".yml" ) ) ;
internalConfigFiles . add ( new DefaultConfigFileMetadata ( namespace , serviceName , "application-" + profile + ".yaml" ) ) ;
}
polarisConfigFilePuller . initCustomPolarisConfigFiles ( compositePropertySource , configFileGroups ) ;
return compositePropertySource ;
// build default config properties files.
internalConfigFiles . add ( new DefaultConfigFileMetadata ( namespace , serviceName , "application.properties" ) ) ;
internalConfigFiles . add ( new DefaultConfigFileMetadata ( namespace , serviceName , "application.yml" ) ) ;
internalConfigFiles . add ( new DefaultConfigFileMetadata ( namespace , serviceName , "application.yaml" ) ) ;
}
private void buildInternalBootstrapConfigFiles ( List < ConfigFileMetadata > internalConfigFiles , String namespace , String serviceName , List < String > profileList ) {
for ( String profile : profileList ) {
if ( ! StringUtils . hasText ( profile ) ) {
continue ;
}
internalConfigFiles . add ( new DefaultConfigFileMetadata ( namespace , serviceName , "bootstrap-" + profile + ".properties" ) ) ;
internalConfigFiles . add ( new DefaultConfigFileMetadata ( namespace , serviceName , "bootstrap-" + profile + ".yml" ) ) ;
internalConfigFiles . add ( new DefaultConfigFileMetadata ( namespace , serviceName , "bootstrap-" + profile + ".yaml" ) ) ;
}
// build default config properties files.
internalConfigFiles . add ( new DefaultConfigFileMetadata ( namespace , serviceName , "bootstrap.properties" ) ) ;
internalConfigFiles . add ( new DefaultConfigFileMetadata ( namespace , serviceName , "bootstrap.yml" ) ) ;
internalConfigFiles . add ( new DefaultConfigFileMetadata ( namespace , serviceName , "bootstrap.yaml" ) ) ;
}
private void initCustomPolarisConfigFiles ( CompositePropertySource compositePropertySource , List < ConfigFileGroup > configFileGroups ) {
String namespace = polarisContextProperties . getNamespace ( ) ;
for ( ConfigFileGroup configFileGroup : configFileGroups ) {
String group = configFileGroup . getName ( ) ;
if ( ! StringUtils . hasText ( group ) ) {
throw new IllegalArgumentException ( "polaris config group name cannot be empty." ) ;
}
List < String > files = configFileGroup . getFiles ( ) ;
if ( CollectionUtils . isEmpty ( files ) ) {
return ;
}
for ( String fileName : files ) {
PolarisPropertySource polarisPropertySource = loadPolarisPropertySource ( namespace , group , fileName ) ;
compositePropertySource . addPropertySource ( polarisPropertySource ) ;
polarisPropertySourceManager . addPropertySource ( polarisPropertySource ) ;
LOGGER . info ( "[SCT Config] Load and inject polaris config file success. namespace = {}, group = {}, fileName = {}" , namespace , group , fileName ) ;
}
}
}
private PolarisPropertySource loadPolarisPropertySource ( String namespace , String group , String fileName ) {
ConfigKVFile configKVFile ;
// unknown extension is resolved as properties file
if ( ConfigFileFormat . isPropertyFile ( fileName ) | | ConfigFileFormat . isUnknownFile ( fileName ) ) {
configKVFile = configFileService . getConfigPropertiesFile ( namespace , group , fileName ) ;
}
else if ( ConfigFileFormat . isYamlFile ( fileName ) ) {
configKVFile = configFileService . getConfigYamlFile ( namespace , group , fileName ) ;
}
else {
LOGGER . warn ( "[SCT Config] Unsupported config file. namespace = {}, group = {}, fileName = {}" , namespace , group , fileName ) ;
throw new IllegalStateException ( "Only configuration files in the format of properties / yaml / yaml" + " can be injected into the spring context" ) ;
}
Map < String , Object > map = new ConcurrentHashMap < > ( ) ;
for ( String key : configKVFile . getPropertyNames ( ) ) {
map . put ( key , configKVFile . getProperty ( key , null ) ) ;
}
return new PolarisPropertySource ( namespace , group , fileName , configKVFile , map ) ;
}
}