Commit c61e54e4 authored by liaozan's avatar liaozan 🏀

Polish ConfigurableProperties load

parent f2781612
package com.schbrain.common.util;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.google.common.base.CaseFormat;
import com.google.common.base.Converter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.core.annotation.MergedAnnotation;
import java.util.Collections;
......@@ -22,11 +24,11 @@ public class ConfigurationPropertiesUtils {
return toMap(source, true);
}
public static Map<String, Object> toMap(Object source, boolean ignoreNull) {
public static Map<String, Object> toMap(Object source, boolean ignoreNullValue) {
return toMap(source, true, DEFAULT_CONVERTER);
}
public static Map<String, Object> toMap(Object source, boolean ignoreNull, Converter<String, String> converter) {
public static Map<String, Object> toMap(Object source, boolean ignoreNullValue, Converter<String, String> converter) {
if (source == null) {
return Collections.emptyMap();
}
......@@ -35,14 +37,23 @@ public class ConfigurationPropertiesUtils {
if (sourceClass.isAnnotationPresent(ConfigurationProperties.class)) {
String prefix = getPrefix(sourceClass);
Map<String, Object> sourceMap = new LinkedHashMap<>();
return BeanUtil.beanToMap(source, sourceMap, ignoreNull, key -> prefix + "." + converter.convert(key));
CopyOptions copyOptions = CopyOptions.create()
.setIgnoreNullValue(ignoreNullValue)
.setPropertiesFilter((field, value) -> !field.isAnnotationPresent(NestedConfigurationProperty.class))
.setFieldNameEditor(key -> prefix + "." + converter.convert(key));
return BeanUtil.beanToMap(source, sourceMap, copyOptions);
}
return BeanUtil.beanToMap(source);
}
public static String getPrefix(Class<?> sourceClass) {
ConfigurationProperties configurationProperties = sourceClass.getAnnotation(ConfigurationProperties.class);
MergedAnnotation<ConfigurationProperties> mergedAnnotation = MergedAnnotation.from(configurationProperties);
ConfigurationProperties annotation = sourceClass.getAnnotation(ConfigurationProperties.class);
if (annotation == null) {
String className = ConfigurationProperties.class.getName();
String errorDetail = sourceClass.getSimpleName() + " must annotated @" + className + " or overwrite getPropertiesPrefix method";
throw new IllegalStateException(errorDetail);
}
MergedAnnotation<ConfigurationProperties> mergedAnnotation = MergedAnnotation.from(annotation);
return mergedAnnotation.getString(MergedAnnotation.VALUE);
}
......
package com.schbrain.common.util.support;
import com.schbrain.common.util.ConfigurationPropertiesUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.core.Ordered;
......@@ -33,13 +32,7 @@ public interface ConfigurableProperties extends Ordered {
/**
* the prefix of properties
*/
private String getPropertiesPrefix() {
ConfigurationProperties annotation = getClass().getAnnotation(ConfigurationProperties.class);
if (annotation == null) {
String className = ConfigurationProperties.class.getName();
String errorDetail = getClass().getSimpleName() + " must annotated @" + className + " or overwrite getPrefix method";
throw new IllegalStateException(errorDetail);
}
default String getPropertiesPrefix() {
return ConfigurationPropertiesUtils.getPrefix(getClass());
}
......
......@@ -2,13 +2,15 @@ package com.schbrain.framework.autoconfigure.apollo;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import com.google.common.collect.Maps;
import com.schbrain.common.util.ConfigurationPropertiesUtils;
import com.schbrain.common.util.support.ConfigurableProperties;
import com.schbrain.framework.autoconfigure.apollo.config.OrderedMapPropertySource;
import com.schbrain.framework.autoconfigure.apollo.event.ConfigLoadedEvent;
import com.schbrain.framework.autoconfigure.apollo.event.listener.ConfigLoadedEventListener;
import com.schbrain.framework.autoconfigure.apollo.properties.ApolloProperties;
import com.schbrain.framework.autoconfigure.apollo.util.ConfigUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.logging.Log;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplication;
......@@ -18,10 +20,11 @@ import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.core.ResolvableType;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.util.ClassUtils;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.Map.Entry;
import static org.springframework.core.io.support.SpringFactoriesLoader.loadFactories;
......@@ -47,7 +50,7 @@ class ConfigurablePropertiesLoader {
void load(ConfigurableEnvironment environment, SpringApplication application) {
List<ConfigurableProperties> propertiesList = loadFactories(ConfigurableProperties.class, getClass().getClassLoader());
if (CollectionUtils.isEmpty(propertiesList)) {
log.warn("There is no configuration properties found");
log.warn("There is no configurable properties found");
return;
}
......@@ -55,33 +58,34 @@ class ConfigurablePropertiesLoader {
boolean remoteFirst = ApolloProperties.get(environment).isRemoteFirst();
for (ConfigurableProperties properties : propertiesList) {
OrderedMapPropertySource propertySource = loadFromRemote(environment, remoteFirst, properties.getNamespace());
if (propertySource == null) {
continue;
}
// multicast event
OrderedMapPropertySource propertySource = buildPropertySource(environment, remoteFirst, properties);
ConfigLoadedEvent event = createEvent(environment, application, propertySource, properties);
eventMulticaster.multicastEvent(event, ResolvableType.forClass(event.getClass()));
}
}
private OrderedMapPropertySource loadFromRemote(ConfigurableEnvironment environment, boolean remoteFirst, String namespace) {
Config config = ConfigService.getConfig(namespace);
OrderedMapPropertySource propertySource = ConfigUtils.toPropertySource(namespace, config);
if (propertySource == null) {
log.warn("No configuration properties loaded under namespace: " + namespace);
return null;
}
private OrderedMapPropertySource buildPropertySource(ConfigurableEnvironment environment, boolean remoteFirst, ConfigurableProperties properties) {
Map<String, Object> mergedProperties = loadAndMergeLocalDefaults(properties);
OrderedMapPropertySource propertySource = createPropertySource(environment, properties.getNamespace(), mergedProperties);
if (remoteFirst) {
environment.getPropertySources().addFirst(propertySource);
} else {
environment.getPropertySources().addLast(propertySource);
}
// resolve any placeHolders
ConfigUtils.resolvePlaceHolders(environment, propertySource);
return propertySource;
}
private Map<String, Object> loadAndMergeLocalDefaults(ConfigurableProperties properties) {
String namespace = properties.getNamespace();
Config config = ConfigService.getConfig(namespace);
Map<String, Object> loadedProperties = toPropertiesMap(config);
if (MapUtils.isEmpty(loadedProperties)) {
log.warn("No configuration properties loaded under namespace: " + namespace);
}
Map<String, Object> defaultProperties = ConfigurationPropertiesUtils.toMap(properties);
return mergeProperties(loadedProperties, defaultProperties);
}
private ConfigLoadedEvent createEvent(ConfigurableEnvironment environment, SpringApplication application,
OrderedMapPropertySource propertySource, ConfigurableProperties properties) {
ConfigurableProperties boundProperties = properties.bind(environment);
......@@ -98,4 +102,35 @@ class ConfigurablePropertiesLoader {
return eventMulticaster;
}
private Map<String, Object> toPropertiesMap(Config config) {
Set<String> propertyNames = config.getPropertyNames();
if (propertyNames.isEmpty()) {
return Collections.emptyMap();
}
Map<String, Object> configs = Maps.newLinkedHashMapWithExpectedSize(propertyNames.size());
for (String propertyName : propertyNames) {
String property = config.getProperty(propertyName, null);
configs.put(propertyName, property);
}
return configs;
}
private Map<String, Object> mergeProperties(Map<String, Object> loadedProperties, Map<String, Object> defaultProperties) {
Map<String, Object> mergedProperties = new LinkedHashMap<>();
mergedProperties.putAll(defaultProperties);
mergedProperties.putAll(loadedProperties);
return mergedProperties;
}
private OrderedMapPropertySource createPropertySource(Environment environment, String namespace, Map<String, Object> source) {
for (Entry<String, Object> entry : source.entrySet()) {
Object value = entry.getValue();
if (value instanceof String) {
String resolvedValue = environment.resolvePlaceholders((String) value);
source.put(entry.getKey(), resolvedValue);
}
}
return new OrderedMapPropertySource(namespace, source);
}
}
......@@ -13,15 +13,15 @@ import java.util.Map;
*/
public class OrderedMapPropertySource extends MapPropertySource {
public OrderedMapPropertySource(String name, Map<String, String> source) {
public OrderedMapPropertySource(String name, Map<String, Object> source) {
super(name, new LinkedHashMap<>(source));
}
public void addProperties(Map<String, String> properties) {
public void addProperties(Map<String, Object> properties) {
getSource().putAll(properties);
}
public void addProperty(String propertyName, String propertyValue) {
public void addProperty(String propertyName, Object propertyValue) {
getSource().put(propertyName, propertyValue);
}
......
package com.schbrain.framework.autoconfigure.apollo.util;
import com.ctrip.framework.apollo.Config;
import com.google.common.collect.Maps;
import com.schbrain.framework.autoconfigure.apollo.config.OrderedMapPropertySource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.ConfigurableEnvironment;
import javax.annotation.Nullable;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* @author liaozan
* @since 2021/12/6
*/
@Slf4j
public class ConfigUtils {
@Nullable
public static OrderedMapPropertySource toPropertySource(String name, Config config) {
Set<String> propertyNames = config.getPropertyNames();
if (propertyNames.isEmpty()) {
return null;
}
Map<String, String> configs = Maps.newLinkedHashMapWithExpectedSize(propertyNames.size());
for (String propertyName : propertyNames) {
String property = config.getProperty(propertyName, null);
configs.put(propertyName, property);
}
return new OrderedMapPropertySource(name, configs);
}
public static void resolvePlaceHolders(ConfigurableEnvironment environment, OrderedMapPropertySource propertySource) {
Map<String, Object> source = propertySource.getSource();
for (Entry<String, Object> entry : source.entrySet()) {
Object value = entry.getValue();
if (value instanceof String) {
String resolvedValue = environment.resolvePlaceholders((String) value);
source.put(entry.getKey(), resolvedValue);
}
}
}
}
\ No newline at end of file
......@@ -43,7 +43,7 @@ public class LoggerConfigLoadedEventListener extends GenericConfigLoadedEventLis
@Override
protected void onConfigLoaded(ConfigLoadedEvent event, LoggerProperties properties) {
HostInfo hostInfo = InetUtils.findFirstNonLoopBackHostInfo();
Map<String, String> hostInfoProperties = buildHostInfoProperties(hostInfo);
Map<String, Object> hostInfoProperties = buildHostInfoProperties(hostInfo);
event.getPropertySource().addProperties(hostInfoProperties);
configLoggingFileLocation(event.getEnvironment(), properties.getLogConfigNamespace());
this.loggerInitializer = new LoggerConfigurationInitializer(event.getEnvironment(), properties, hostInfo);
......@@ -52,8 +52,8 @@ public class LoggerConfigLoadedEventListener extends GenericConfigLoadedEventLis
/**
* hostInfo properties, for logging pattern
*/
private Map<String, String> buildHostInfoProperties(HostInfo hostInfo) {
Map<String, String> properties = Maps.newHashMapWithExpectedSize(2);
private Map<String, Object> buildHostInfoProperties(HostInfo hostInfo) {
Map<String, Object> properties = Maps.newHashMapWithExpectedSize(2);
properties.put("application.hostname", hostInfo.getHostname());
properties.put("application.ipAddress", hostInfo.getIpAddress());
return properties;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment