Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

apollo跟jasypt-spring-boot-2.1.0.jar不兼容 #2162

Closed
XiangNick opened this issue Apr 24, 2019 · 3 comments
Closed

apollo跟jasypt-spring-boot-2.1.0.jar不兼容 #2162

XiangNick opened this issue Apr 24, 2019 · 3 comments
Projects

Comments

@XiangNick
Copy link

场景:同样的配置,两个工程。工程A无jasypt-spring-boot-2.1.0.jar依赖,工程B有。结果普通的Spring Placeholder配置,远程修改后。工程A可实时刷新,工程B不行。

原因:apollo在启动时,在PropertySourcesProcessor里,特意将自己的CompositePropertySource放在最前面,以确保在配置更新时能从environment拿到最新的配置跟远程服务通知的配置比对。在com.ctrip.framework.apollo.spring.property.AutoUpdateConfigChangeListener#shouldTriggerAutoUpdate方法中,如果从environment里拿到的配置跟远程通知的配置不同,则就算接收到了远程的通知,也不更新配置。

而jasypt-spring-boot这个jar,是在springboot工程中常用的加密敏感配置如数据库配置的jar。而jasyptspringboot的EncryptableEnumerablePropertySourceWrapper实现了PropertySource接口并代理了默认的CompositePropertySource,他的getProperty方法,走到的是com.ulisesbocchio.jasyptspringboot.caching.CachingDelegateEncryptablePropertySource的getProperty方法,是直接从一个ConcurrentMapCache的缓存中读取配置。

这样就导致在接入apollo的客户端工程里,如果引入了jasypt-spring-boot,在org.springframework.core.env.PropertySourcesPropertyResolver#getProperty方法中,由于jasypt代理了默认apollo使用的CompositePropertySource,并且将启动时的配置存入缓存,这样每次接收到远程配置变更通知时,jasypt的EncryptableEnumerablePropertySourceWrapper都会从ConcurrentMapCache的缓存中读取配置,而非从CompositePropertySource里实时读取配置,这样就会导致引入了jasypt-spring-boot的apollo客户端,无法实时更新配置。

@tonyd1989
Copy link

我这边也发现了这个问题,加入jasypt-spring-boot-2.1.0.jar后,更新配置不生效,查询源码,应该是同样的原因

@nobodyiam nobodyiam added this to WIP in Apollo Apr 26, 2019
nobodyiam added a commit to nobodyiam/apollo that referenced this issue Apr 27, 2019
…ppers like jasypt, so we won't be able to decide whether to trigger this change or not.

So it's better just to trigger it as it is idempotent.
@nobodyiam nobodyiam mentioned this issue Apr 27, 2019
@nobodyiam nobodyiam moved this from WIP to Done in Apollo Apr 27, 2019
@nobodyiam
Copy link
Member

@XiangNick

看了一下jasypt-spring-boot 2.1.0确实有这个问题,建议使用1.16版本,可以参考apollo-use-cases中的spring-boot-encrypt

@wujinqing
Copy link

wujinqing commented Jun 18, 2021

下面是我的一种解决方案:
1.CachingDelegateEncryptablePropertySource自带了一个refresh()可以清理缓存。
2.参考jaspyt自带的com.ulisesbocchio.jasyptspringboot.caching.RefreshScopeRefreshedEventListener刷新缓存的方案。
3.我自己写了一个类似的类:
public class JaspytRefreshScopeRefreshedEventListener {
private final ConfigurableEnvironment environment;
private final EncryptablePropertySourceConverter converter;

public JaspytRefreshScopeRefreshedEventListener(ConfigurableEnvironment environment, EncryptablePropertySourceConverter converter) {
    this.environment = environment;
    this.converter = converter;
}

public void refresh() {
    refreshCachedProperties();
    decorateNewSources();
}

private void decorateNewSources() {
    MutablePropertySources propSources = environment.getPropertySources();
    converter.convertPropertySources(propSources);
}

private void refreshCachedProperties() {
    PropertySources propertySources = environment.getPropertySources();
    propertySources.forEach(this::refreshPropertySource);
}

@SuppressWarnings("rawtypes")
private void refreshPropertySource(PropertySource<?> propertySource) {
    if (propertySource instanceof CompositePropertySource) {
        CompositePropertySource cps = (CompositePropertySource) propertySource;
        cps.getPropertySources().forEach(this::refreshPropertySource);
    } else if (propertySource instanceof EncryptablePropertySource) {
        EncryptablePropertySource eps = (EncryptablePropertySource) propertySource;
        eps.refresh();
    }
}

}

4.自定义一个ApolloConfigChangeListener监听器,在onChange()方法中判断更新的属性值如果以“ENC(”开头则,调用第3步的类的刷新方法,刷新缓存。
public class ApolloConfigChangeListener implements ConfigChangeListener {
private JaspytRefreshScopeRefreshedEventListener listener;

public ApolloConfigChangeListener() {
}

public void lazySet(JaspytRefreshScopeRefreshedEventListener listener)
{
    this.listener = listener;
}
@Override
public void onChange(ConfigChangeEvent changeEvent) {
    changeEvent.changedKeys().forEach(k -> {
        ConfigChange configChange = changeEvent.getChange(k);

        String propertyName = configChange.getPropertyName();
        String newValue = configChange.getNewValue();
        PropertyChangeType changeType = configChange.getChangeType();

        if(newValue.startsWith("ENC(") && Assert.isNotNull(this.listener))
        {
            this.listener.refresh();
        }
    });
}

}
5.通过这个方法在我在最新版本jasypt-spring-boot:3.0.3,也能实现Apollo的字段刷新。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Apollo
  
Archived
Development

No branches or pull requests

4 participants