Commit c61e54e4 authored by liaozan's avatar liaozan 🏀

Polish ConfigurableProperties load

parent f2781612
package com.schbrain.common.util; package com.schbrain.common.util;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.google.common.base.CaseFormat; import com.google.common.base.CaseFormat;
import com.google.common.base.Converter; import com.google.common.base.Converter;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.MergedAnnotation;
import java.util.Collections; import java.util.Collections;
...@@ -22,11 +24,11 @@ public class ConfigurationPropertiesUtils { ...@@ -22,11 +24,11 @@ public class ConfigurationPropertiesUtils {
return toMap(source, true); 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); 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) { if (source == null) {
return Collections.emptyMap(); return Collections.emptyMap();
} }
...@@ -35,14 +37,23 @@ public class ConfigurationPropertiesUtils { ...@@ -35,14 +37,23 @@ public class ConfigurationPropertiesUtils {
if (sourceClass.isAnnotationPresent(ConfigurationProperties.class)) { if (sourceClass.isAnnotationPresent(ConfigurationProperties.class)) {
String prefix = getPrefix(sourceClass); String prefix = getPrefix(sourceClass);
Map<String, Object> sourceMap = new LinkedHashMap<>(); 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); return BeanUtil.beanToMap(source);
} }
public static String getPrefix(Class<?> sourceClass) { public static String getPrefix(Class<?> sourceClass) {
ConfigurationProperties configurationProperties = sourceClass.getAnnotation(ConfigurationProperties.class); ConfigurationProperties annotation = sourceClass.getAnnotation(ConfigurationProperties.class);
MergedAnnotation<ConfigurationProperties> mergedAnnotation = MergedAnnotation.from(configurationProperties); 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); return mergedAnnotation.getString(MergedAnnotation.VALUE);
} }
......
package com.schbrain.common.util.support; package com.schbrain.common.util.support;
import com.schbrain.common.util.ConfigurationPropertiesUtils; 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.Bindable;
import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
...@@ -33,13 +32,7 @@ public interface ConfigurableProperties extends Ordered { ...@@ -33,13 +32,7 @@ public interface ConfigurableProperties extends Ordered {
/** /**
* the prefix of properties * the prefix of properties
*/ */
private String getPropertiesPrefix() { default 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);
}
return ConfigurationPropertiesUtils.getPrefix(getClass()); return ConfigurationPropertiesUtils.getPrefix(getClass());
} }
......
...@@ -2,13 +2,15 @@ package com.schbrain.framework.autoconfigure.apollo; ...@@ -2,13 +2,15 @@ package com.schbrain.framework.autoconfigure.apollo;
import com.ctrip.framework.apollo.Config; import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService; 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.common.util.support.ConfigurableProperties;
import com.schbrain.framework.autoconfigure.apollo.config.OrderedMapPropertySource; import com.schbrain.framework.autoconfigure.apollo.config.OrderedMapPropertySource;
import com.schbrain.framework.autoconfigure.apollo.event.ConfigLoadedEvent; import com.schbrain.framework.autoconfigure.apollo.event.ConfigLoadedEvent;
import com.schbrain.framework.autoconfigure.apollo.event.listener.ConfigLoadedEventListener; import com.schbrain.framework.autoconfigure.apollo.event.listener.ConfigLoadedEventListener;
import com.schbrain.framework.autoconfigure.apollo.properties.ApolloProperties; 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.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.springframework.boot.ConfigurableBootstrapContext; import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
...@@ -18,10 +20,11 @@ import org.springframework.context.event.ApplicationEventMulticaster; ...@@ -18,10 +20,11 @@ import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.SimpleApplicationEventMulticaster; import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import java.util.List; import java.util.*;
import java.util.Set; import java.util.Map.Entry;
import static org.springframework.core.io.support.SpringFactoriesLoader.loadFactories; import static org.springframework.core.io.support.SpringFactoriesLoader.loadFactories;
...@@ -47,7 +50,7 @@ class ConfigurablePropertiesLoader { ...@@ -47,7 +50,7 @@ class ConfigurablePropertiesLoader {
void load(ConfigurableEnvironment environment, SpringApplication application) { void load(ConfigurableEnvironment environment, SpringApplication application) {
List<ConfigurableProperties> propertiesList = loadFactories(ConfigurableProperties.class, getClass().getClassLoader()); List<ConfigurableProperties> propertiesList = loadFactories(ConfigurableProperties.class, getClass().getClassLoader());
if (CollectionUtils.isEmpty(propertiesList)) { if (CollectionUtils.isEmpty(propertiesList)) {
log.warn("There is no configuration properties found"); log.warn("There is no configurable properties found");
return; return;
} }
...@@ -55,33 +58,34 @@ class ConfigurablePropertiesLoader { ...@@ -55,33 +58,34 @@ class ConfigurablePropertiesLoader {
boolean remoteFirst = ApolloProperties.get(environment).isRemoteFirst(); boolean remoteFirst = ApolloProperties.get(environment).isRemoteFirst();
for (ConfigurableProperties properties : propertiesList) { for (ConfigurableProperties properties : propertiesList) {
OrderedMapPropertySource propertySource = loadFromRemote(environment, remoteFirst, properties.getNamespace()); OrderedMapPropertySource propertySource = buildPropertySource(environment, remoteFirst, properties);
if (propertySource == null) {
continue;
}
// multicast event
ConfigLoadedEvent event = createEvent(environment, application, propertySource, properties); ConfigLoadedEvent event = createEvent(environment, application, propertySource, properties);
eventMulticaster.multicastEvent(event, ResolvableType.forClass(event.getClass())); eventMulticaster.multicastEvent(event, ResolvableType.forClass(event.getClass()));
} }
} }
private OrderedMapPropertySource loadFromRemote(ConfigurableEnvironment environment, boolean remoteFirst, String namespace) { private OrderedMapPropertySource buildPropertySource(ConfigurableEnvironment environment, boolean remoteFirst, ConfigurableProperties properties) {
Config config = ConfigService.getConfig(namespace); Map<String, Object> mergedProperties = loadAndMergeLocalDefaults(properties);
OrderedMapPropertySource propertySource = ConfigUtils.toPropertySource(namespace, config); OrderedMapPropertySource propertySource = createPropertySource(environment, properties.getNamespace(), mergedProperties);
if (propertySource == null) {
log.warn("No configuration properties loaded under namespace: " + namespace);
return null;
}
if (remoteFirst) { if (remoteFirst) {
environment.getPropertySources().addFirst(propertySource); environment.getPropertySources().addFirst(propertySource);
} else { } else {
environment.getPropertySources().addLast(propertySource); environment.getPropertySources().addLast(propertySource);
} }
// resolve any placeHolders
ConfigUtils.resolvePlaceHolders(environment, propertySource);
return 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, private ConfigLoadedEvent createEvent(ConfigurableEnvironment environment, SpringApplication application,
OrderedMapPropertySource propertySource, ConfigurableProperties properties) { OrderedMapPropertySource propertySource, ConfigurableProperties properties) {
ConfigurableProperties boundProperties = properties.bind(environment); ConfigurableProperties boundProperties = properties.bind(environment);
...@@ -98,4 +102,35 @@ class ConfigurablePropertiesLoader { ...@@ -98,4 +102,35 @@ class ConfigurablePropertiesLoader {
return eventMulticaster; 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; ...@@ -13,15 +13,15 @@ import java.util.Map;
*/ */
public class OrderedMapPropertySource extends MapPropertySource { 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)); super(name, new LinkedHashMap<>(source));
} }
public void addProperties(Map<String, String> properties) { public void addProperties(Map<String, Object> properties) {
getSource().putAll(properties); getSource().putAll(properties);
} }
public void addProperty(String propertyName, String propertyValue) { public void addProperty(String propertyName, Object propertyValue) {
getSource().put(propertyName, 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 ...@@ -43,7 +43,7 @@ public class LoggerConfigLoadedEventListener extends GenericConfigLoadedEventLis
@Override @Override
protected void onConfigLoaded(ConfigLoadedEvent event, LoggerProperties properties) { protected void onConfigLoaded(ConfigLoadedEvent event, LoggerProperties properties) {
HostInfo hostInfo = InetUtils.findFirstNonLoopBackHostInfo(); HostInfo hostInfo = InetUtils.findFirstNonLoopBackHostInfo();
Map<String, String> hostInfoProperties = buildHostInfoProperties(hostInfo); Map<String, Object> hostInfoProperties = buildHostInfoProperties(hostInfo);
event.getPropertySource().addProperties(hostInfoProperties); event.getPropertySource().addProperties(hostInfoProperties);
configLoggingFileLocation(event.getEnvironment(), properties.getLogConfigNamespace()); configLoggingFileLocation(event.getEnvironment(), properties.getLogConfigNamespace());
this.loggerInitializer = new LoggerConfigurationInitializer(event.getEnvironment(), properties, hostInfo); this.loggerInitializer = new LoggerConfigurationInitializer(event.getEnvironment(), properties, hostInfo);
...@@ -52,8 +52,8 @@ public class LoggerConfigLoadedEventListener extends GenericConfigLoadedEventLis ...@@ -52,8 +52,8 @@ public class LoggerConfigLoadedEventListener extends GenericConfigLoadedEventLis
/** /**
* hostInfo properties, for logging pattern * hostInfo properties, for logging pattern
*/ */
private Map<String, String> buildHostInfoProperties(HostInfo hostInfo) { private Map<String, Object> buildHostInfoProperties(HostInfo hostInfo) {
Map<String, String> properties = Maps.newHashMapWithExpectedSize(2); Map<String, Object> properties = Maps.newHashMapWithExpectedSize(2);
properties.put("application.hostname", hostInfo.getHostname()); properties.put("application.hostname", hostInfo.getHostname());
properties.put("application.ipAddress", hostInfo.getIpAddress()); properties.put("application.ipAddress", hostInfo.getIpAddress());
return properties; 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