问题描述: Maven多模块开发, SSM框架改造成SpringBoot框架, 集成apollo时,读取不到apollo的配置.
因为是自己封装了PropertyPlaceholderConfigurer进行配置文件的读取:
/**
*获取到当前架包中资源文件夹下的Properties配置文件
*/
public class PropertyConfigurer extends PropertyPlaceholderConfigurer {
private static Map<String,String> ctxPropMap;
@Override
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException {
super.processProperties(beanFactoryToProcess, props);
ctxPropMap = new HashMap<String,String>(16);
for (Object key : props.keySet()){
String keyStr = key.toString();
String value = String.valueOf(props.get(keyStr));
ctxPropMap.put(keyStr,value);
}
}
/**
*获取注解
*@param name
*@return
*/
public static String getCtxProp(String name) {
return ctxPropMap.get(name);
}
}
所以需要将本地配置和apollo配置整合起来.
参考apollo github wiki - Java客户端使用指南3.2 Spring整合方式:
人家官方已经不推荐使用PropertyPlaceholderConfigurer, 推荐用PropertySourcesPlaceholderConfigurer.
难点是, 如何将apollo中的配置读取出来, 和本地配置整合在一起.
但是我知道, apollo的配置会加载到environment中, 于是我便注入environment.
@Autowired
ConfigurableEnvironment environment;
注入的environment为空怎么办?
在改造过程中了解过SpringBoot如何实现自动配置, 看源码的时候学到一招, 就是使用回调.
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
这样一来, 我解决了注入Environment为空的问题.
再一个难点就是, 如何从Environment中读取到apollo中的配置.
参考apollo的源码, 我了解到apollo配置加载到环境中最重要的一部分, 下面是apollo的源码可以参考一下:
package com.ctrip.framework.apollo.spring.boot;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.spring.config.ConfigPropertySourceFactory;
import com.ctrip.framework.apollo.spring.config.PropertySourcesConstants;
import com.ctrip.framework.apollo.spring.util.SpringInjector;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
/**
* Initialize apollo system properties and inject the Apollo config in Spring Boot bootstrap phase
*
* <p>Configuration example:</p>
* <pre class="code">
* # set app.id
* app.id = 100004458
* # enable apollo bootstrap config and inject 'application' namespace in bootstrap phase
* apollo.bootstrap.enabled = true
* </pre>
*
* or
*
* <pre class="code">
* # set app.id
* app.id = 100004458
* # enable apollo bootstrap config
* apollo.bootstrap.enabled = true
* # will inject 'application' and 'FX.apollo' namespaces in bootstrap phase
* apollo.bootstrap.namespaces = application,FX.apollo
* </pre>
*/
public class ApolloApplicationContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
private static final Logger logger = LoggerFactory.getLogger(ApolloApplicationContextInitializer.class);
private static final Splitter NAMESPACE_SPLITTER = Splitter.on(",").omitEmptyStrings().trimResults();
private static final String[] APOLLO_SYSTEM_PROPERTIES = {"app.id", ConfigConsts.APOLLO_CLUSTER_KEY,
"apollo.cacheDir", ConfigConsts.APOLLO_META_KEY};
private final ConfigPropertySourceFactory configPropertySourceFactory = SpringInjector
.getInstance(ConfigPropertySourceFactory.class);
@Override
public void initialize(ConfigurableApplicationContext context) {
ConfigurableEnvironment environment = context.getEnvironment();
initializeSystemProperty(environment);
String enabled = environment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED, "false");
if (!Boolean.valueOf(enabled)) {
logger.debug("Apollo bootstrap config is not enabled for context {}, see property: ${{}}", context, PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED);
return;
}
logger.debug("Apollo bootstrap config is enabled for context {}", context);
if (environment.getPropertySources().contains(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
//already initialized
return;
}
String namespaces = environment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_NAMESPACES, ConfigConsts.NAMESPACE_APPLICATION);
logger.debug("Apollo bootstrap namespaces: {}", namespaces);
List<String> namespaceList = NAMESPACE_SPLITTER.splitToList(namespaces);
CompositePropertySource composite = new CompositePropertySource(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME);
for (String namespace : namespaceList) {
Config config = ConfigService.getConfig(namespace);
composite.addPropertySource(configPropertySourceFactory.getConfigPropertySource(namespace, config));
}
environment.getPropertySources().addFirst(composite);
}
/**
* To fill system properties from environment config
*/
void initializeSystemProperty(ConfigurableEnvironment environment) {
for (String propertyName : APOLLO_SYSTEM_PROPERTIES) {
fillSystemPropertyFromEnvironment(environment, propertyName);
}
}
private void fillSystemPropertyFromEnvironment(ConfigurableEnvironment environment, String propertyName) {
if (System.getProperty(propertyName) != null) {
return;
}
String propertyValue = environment.getProperty(propertyName);
if (Strings.isNullOrEmpty(propertyValue)) {
return;
}
System.setProperty(propertyName, propertyValue);
}
}
看到这一步
我好像明白了很多.
所以我的PropertyConfigurer最终为:
/**
* 获取到当前架包中资源文件夹下的Properties配置文件
*/
public class PropertyConfigurer extends PropertySourcesPlaceholderConfigurer {
private static Map<String,String> ctxPropMap;
private static final Logger LOGGER = LoggerFactory.getLogger(PropertyConfigurer.class);
@Autowired
ConfigurableEnvironment environment;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
try {
Properties properties = super.mergeProperties();
ctxPropMap = new HashMap<String,String>(16);
CompositePropertySource propertySource = (CompositePropertySource) environment.getPropertySources().get("ApolloBootstrapPropertySources");
if (propertySource != null){
// Apollo管理的配置放入ctxPropMap
for (String name : propertySource.getPropertyNames()){
ctxPropMap.put(name, environment.getProperty(name));
}
}
// 本地管理的配置放入ctxPropMap
for (Object key : properties.keySet()){
String keyStr = key.toString();
String value = String.valueOf(properties.get(keyStr));
ctxPropMap.put(keyStr,value);
}
} catch (IOException e) {
e.printStackTrace();
LOGGER.error("Error occurred when return a merged Properties instance containing both the loaded properties and properties set on this FactoryBean.");
}
}
/**
* 获取注解
* @param name
* @return
*/
public static String getCtxProp(String name) {
return ctxPropMap.get(name);
}
/**
* 获取HashMap键值对
* @return
*/
public static Map<String, String> getCtxPropMap() {
return ctxPropMap;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = (ConfigurableEnvironment) environment;
}
}
最重要的一行代码:
CompositePropertySource propertySource = (CompositePropertySource) environment.getPropertySources().get("ApolloBootstrapPropertySources");
职场小白, 如有错误, 还望及时批评指正, 感谢!!!