Java

Springboot 中使用阿里云ACM配置中心

2019-10-23  本文已影响0人  Vchar_Fred

当我们的项目只是一个简单的Springboot项目时,想实现Springboot启动时加载读取远程的数据库或者redis等配置信息时,使用阿里云ACM配置中心就有诸多不便了。官方提供的sdk包要么需要使用SpringCloud或者是刚出来的nocos做注册中心;因此只能自力更生了。

实现原理

参考了一下SpringCloud的实现方式,在下面这个类中实现了配置信息的重载:org.springframework.cloud.bootstrap.BootstrapApplicationListener

public class BootstrapApplicationListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered 
{
...
  [@Override](https://my.oschina.net/u/1162528)
  public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
   ....
   }
   ...

这个类实现了一个ApplicationEnvironmentPreparedEventListener的接口,并在spring.factories文件进行了配置,这样在springboot启动加载准备系统配置信息时就会自动加载这个类。这个类在此时就会去加载和更新相关配置信息,既然可以这样操作那么我们也一定可以做个类似的简化操作。

去调试springboot启动时的过程时,你会发现这个类:org.springframework.boot.context.config.ConfigFileApplicationListener

它会去根据序号执行所有的EnvironmentPostProcessor的实现类,而这些正好是springboot读取的相关配置的操作,同时这个类的配置根据order序号正好是最后一个;那么我们也实现这个接口并将其序号设置在这个类的后面。更详细的可以去查看springboot的启动原理。

具体实现:

在项目中的resources目录下创建META-INF目录,在里面创建一个spring.factories文件(不用担心被其他jar包的覆盖)中编写如下配置:

# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=top.vchar.alibaba.acm.ACMConfigEnvironmentPostProcessor

创建ACMConfigEnvironmentPostProcessor类,示例代码如下:


springboot2.x的实现

public class ACMConfigEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
​
    private final DeferredLog logger = new DeferredLog();
​
    /**
     * The default order for the processor.
   *
   * 这将ConfigFileApplicationListener的order值作为初始值+1
     */
    public static final int DEFAULT_ORDER = ConfigFileApplicationListener.DEFAULT_ORDER + 1;
​
    private int order = DEFAULT_ORDER;
​
    [@Override](https://my.oschina.net/u/1162528)
    public int getOrder() {
        return this.order;//order越大越后执行
    }
​
    [@Override](https://my.oschina.net/u/1162528)
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        MutablePropertySources propertySources = environment.getPropertySources();

        // 获取所有springboot的application配置
        List<PropertySource<?>> applicationConfig = propertySources.stream().filter(p -> p instanceof OriginTrackedMapPropertySource && p.getName().contains("applicationConfig")).collect(Collectors.toList());
        if(applicationConfig.size()==0){
            logger.warn("do not find applicationConfig PropertySource");
            return;
        }
​
    //获取配置的acm信息
        AcmProperties acmProperties = new AcmProperties();
        if(applicationConfig.size()==1){
            // only one application config
            loadAcmConfig((OriginTrackedMapPropertySource) applicationConfig.get(0), acmProperties);
        }else {
            for(PropertySource<?> propertySource: applicationConfig){
                loadAcmConfig((OriginTrackedMapPropertySource) propertySource, acmProperties);
            }
            String[] activeProfiles = environment.getActiveProfiles();
            if(activeProfiles!=null && activeProfiles.length>0){
                List<PropertySource<?>> activeSources = propertySources.stream().filter(p -> p instanceof OriginTrackedMapPropertySource && p.getName().contains("applicationConfig") && p.getName().contains(activeProfiles[0])).collect(Collectors.toList());
                if(activeSources.size() > 0){
                    loadAcmConfig((OriginTrackedMapPropertySource) activeSources.get(0), acmProperties);
                }
            }
        }
​
        // TODO 从系统环境变量中获取acm信息覆盖配置文件中的
    ...
    //根据配置信息初始化acm配置服务,使用官方demo即可
    ...
        //拉取远程acm配置的信息
        Map<String, Object> config = loadConfig(acmProperties);
        if(!config.isEmpty()){
            newSource.putAll(config);
        }

    //将获取到配置信息更新到当前环境中
        for(PropertySource<?> propertySource: applicationConfig){
            OriginTrackedMapPropertySource source  = (OriginTrackedMapPropertySource) propertySource;
            source.getSource().putAll(newSource);
        }
    }
}

springboot1.x的实现(以下是和springboot2.x的不同的地方)

// 获取所有springboot的application配置
PropertySource<?> applicationConfigurationProperties = propertySources.get("applicationConfigurationProperties");
if(null==applicationConfigurationProperties){
    logger.warn("don't find applicationConfigurationProperties info");
    return;
}

//从配置环境中获取ACM的配置信息
loadAcmConfig(applicationConfigurationProperties);
从配置环境中获取ACM的配置信息
private AcmProperties loadAcmConfig(PropertySource<?> applicationConfigurationProperties){
    AcmProperties acmProperties = new AcmProperties();
    if(null!=applicationConfigurationProperties.getProperty("alibaba.acm.application-data-id")){
        acmProperties.setApplicationDataId(applicationConfigurationProperties.getProperty("alibaba.acm.application-data-id").toString());
    }
    if(null!=applicationConfigurationProperties.getProperty("alibaba.acm.group")){
        acmProperties.setGroup(applicationConfigurationProperties.getProperty("alibaba.acm.group").toString());
    }
    if(null!=applicationConfigurationProperties.getProperty("alibaba.acm.endpoint")){
        acmProperties.setEndpoint(applicationConfigurationProperties.getProperty("alibaba.acm.endpoint").toString());
    }
    if(null!=applicationConfigurationProperties.getProperty("alibaba.acm.namespace")){
        acmProperties.setNamespace(applicationConfigurationProperties.getProperty("alibaba.acm.namespace").toString());
    }
    if(null!=applicationConfigurationProperties.getProperty("alibaba.acm.access-key")){
        acmProperties.setAccessKey(applicationConfigurationProperties.getProperty("alibaba.acm.access-key").toString());
    }
    if(null!=applicationConfigurationProperties.getProperty("alibaba.acm.secret-key")){
        acmProperties.setSecretKey(applicationConfigurationProperties.getProperty("alibaba.acm.secret-key").toString());
    }
    if(null!=applicationConfigurationProperties.getProperty("alibaba.acm.time-out")){
        acmProperties.setTimeOut(Integer.parseInt(applicationConfigurationProperties.getProperty("alibaba.acm.time-out").toString()));
    }
    if(null!=applicationConfigurationProperties.getProperty("alibaba.acm.ram-role-name")){
        acmProperties.setRamRoleName(applicationConfigurationProperties.getProperty("alibaba.acm.ram-role-name").toString());
    }
    if(null!=applicationConfigurationProperties.getProperty("alibaba.acm.data-id-list")){
        String dataIds = applicationConfigurationProperties.getProperty("alibaba.acm.data-id-list").toString().trim();
        if(dataIds.length()>0){
            acmProperties.setDataIdList(Arrays.asList(dataIds.split(",")));
        }
    }
    if(null!=applicationConfigurationProperties.getProperty("alibaba.acm.open-kms-filter")){
        if("true".equals(applicationConfigurationProperties.getProperty("alibaba.acm.open-kms-filter").toString())){
            acmProperties.setOpenKMSFilter(true);
        }else {
            acmProperties.setOpenKMSFilter(false);
        }
    }else {
        acmProperties.setOpenKMSFilter(false);
    }
    if(null!=applicationConfigurationProperties.getProperty("alibaba.acm.region-id")){
        acmProperties.setRegionId(applicationConfigurationProperties.getProperty("alibaba.acm.region-id").toString());
    }
    return acmProperties;
}
刷新配置环境中的配置信息
List<EnumerableCompositePropertySource> sourceList = (List<EnumerableCompositePropertySource>) applicationConfigurationProperties.getSource();
    EnumerableCompositePropertySource enumerablePropertySource = sourceList.get(0);
    Collection<PropertySource<?>> source2 = enumerablePropertySource.getSource();
    for (PropertySource<?> source : source2) {
        try {
            if (source instanceof PropertiesPropertySource) {
                PropertiesPropertySource propertySource = (PropertiesPropertySource) source;
                Map<String, Object> properties = propertySource.getSource();
                if(properties!=null){
                    newSource.forEach(properties::put);
                }
            } else {
                if (source instanceof MapPropertySource) {
                    MapPropertySource mapPropertySource = (MapPropertySource) source;
                    Map<String, Object> mapSource = mapPropertySource.getSource();
                    if (null != mapSource && !mapSource.isEmpty()) {
                        mapSource.putAll(newSource);
                    }
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
上一篇 下一篇

猜你喜欢

热点阅读