PropertyPlaceholderConfigurer读取配置改造SpringBoot集成apollo, 读取不到配置

问题描述: 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整合方式: 

https://github.com/ctripcorp/apollo/wiki/Java%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97#3213-spring-boot%E9%9B%86%E6%88%90%E6%96%B9%E5%BC%8F%E6%8E%A8%E8%8D%90

人家官方已经不推荐使用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");

职场小白, 如有错误, 还望及时批评指正, 感谢!!! 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值