刷新时设置的 profiles 只是 应用容器之外其他容器的 active profiles

如果要实现动态设置 profiles 的功能,应该放到应用层做:

# 由于 @RefreshScope 的 destroy 生命周期函数在 Bean 每次刷新时都会调用一次,因此可以利用这个机制发布
来做刷新
@PreDestroy
public void des(){
    log.warn("---毁灭者---");
    log.info("current spring.profiles.active {}",env);
    context.publishEvent(new ActiveProfileEvent(this, (ConfigurableEnvironment) environment));
}

@EventListener(ActiveProfileEvent.class)
public void active(ActiveProfileEvent event){
    log.info("try to active");
    mergeThenActiveIfPossible(event.getEnvironment());
}

private String[] mergeThenActiveIfPossible(ConfigurableEnvironment environment) {
    String[] currentProfiles = environment.getActiveProfiles();
    Set<String> latestProfiles = StringUtils.commaDelimitedListToSet((String) LaixPropertySourceRepository.getLatest("spring.profiles.active"));
    for (String profile : currentProfiles) {
        if (!latestProfiles.contains(profile)) {
            return currentProfiles;
        }
    }
    String[] refreshedProfiles = latestProfiles.toArray(new String[0]);
    environment.setActiveProfiles(refreshedProfiles);
    return refreshedProfiles;
}

public class ActiveProfileEvent extends ApplicationEvent {
    private ConfigurableEnvironment environment;

    public ActiveProfileEvent(Object source, ConfigurableEnvironment environment) {
        super(source);
        this.environment = environment;
    }

    public ConfigurableEnvironment getEnvironment() {
        return environment;
    }
}

另一个,如果通过 远程 active profiles 来远程设置 profile,可以实现额外配置拉取,但是也需要重新 watch,同时会使 laix-meta 很蛋疼(前一步骤已经有了)

会导致 Repository 会 laix-config 显示不一致,唯一的解法是 addLast,但是 addLast 还灰度个毛。。。也破坏了整个优先级的约定

后续需要把 LaixPropertySourceRepository 改成队列可能比较好解决这个问题

同时还要添加动态删除的逻辑

loadExtProfilesIfPossible(profiles, loader, composite);

private boolean loadExtProfilesIfPossible(String[] bootProfiles, PropertyLoader loader, CompositePropertySource composite){
    Object exts = LaixPropertySourceRepository.getLatest("spring.profiles.active");
    if(exts instanceof String){
        Set<String> remoteProfiles = StringUtils.commaDelimitedListToSet((String)exts);
        if(!remoteProfiles.containsAll(Arrays.asList(bootProfiles))){
            log.warn("remote profiles {} doesn't contain all the boot profiles {}, none extra profiles will loading", exts, bootProfiles);
        }
        remoteProfiles.removeAll(Arrays.asList(bootProfiles));

        log.info("loading ext profiles {}", remoteProfiles);
        Set<String> extBases = new LinkedHashSet<>();
        for(String profile: remoteProfiles){
            String profilePrefix = laixConfigProperties.appKeyPrefix(profile);
            LaixPropertySource applicationSource = loader.load(profilePrefix, true, LaixConfigProperties.DEFAULT_VERSION);
            composite.addFirstPropertySource(applicationSource);
            ClientKeyValue mayBases = ClientKVHolder.get(laixConfigProperties.appBasesKey(profile));
            if(mayBases!=null){
                extBases.addAll(StringUtils.commaDelimitedListToSet(mayBases.getValue()));
            }
        }

        Set<String> baseGroups = new LinkedHashSet<>();
        extBases.stream().map(baseName-> laixConfigProperties.baseKeyPrefix(baseName)).forEachOrdered(baseGroups::add);

        log.info("loading ext base configurations {}",baseGroups.stream().map(ServerKeyValueUtils::decodeBaseName).collect(Collectors.toList()));

        Set<String> immutableGroups = extBases.stream()
                .filter(b->laixConfigProperties.getImmutableBases().contains(b))
                .map(baseName-> laixConfigProperties.baseKeyPrefix(baseName)).collect(Collectors.toSet());

        baseGroups.removeAll(immutableGroups);

        baseGroups.parallelStream().map(bg->loader.load(bg,true, LaixConfigProperties.DEFAULT_VERSION)).forEachOrdered(composite::addPropertySource);
        immutableGroups.parallelStream().map(bg->loader.load(bg,false, LaixConfigProperties.DEFAULT_VERSION)).forEachOrdered(composite::addPropertySource);

        String preBases = StringUtils.collectionToCommaDelimitedString(laixConfigProperties.getBases());
        String newBases = preBases.concat(",").concat(StringUtils.collectionToCommaDelimitedString(extBases));

        laixConfigProperties.setBases(newBases);
        // 解决缺省情况下,环境中没有 laix.config.bases 配置项,无法动态绑定到 laix-properties 中的问题
        composite.addPropertySource(new MapPropertySource(
                "laix-meta",Collections.singletonMap(LaixConfigProperties.PREFIX+".bases"
                ,newBases)));
        return true;
    }
    return false;
}

watch 解决办法,在 LaixContextRefresher 中添加一个 EventListener 即可

@EventListener(EnvironmentChangeEvent.class)
public void changed(EnvironmentChangeEvent event) {
    if(event.getKeys().contains("spring.profiles.active")){
        startWatch();
    }
}