文章目录
- 1. 前提
- 2. 基本思想
- 3. 实施步骤
- 4. 那些修改以后要重新加载bean的配置自动更新的处理
- 5. 注意事项
- 6. 后续改进
Apollo本身就支持环境隔离,你可以配置不同的environment来实现,当然你也可以给不同环境搭建不同的apollo服务(如果你资源充足的话)。
但是这篇文章讲的是在资源有限的情况下如何实现环境隔离。
1. 前提
该方案的前提是:
- 你只有一个test的apollo服务和一个prod的apollo服务。
- test和prod上都默认只有DEV的environment。这个现状目前你可能没能力修改。
- 你需要用test环境来支持dev,test,beat三套环境的配置,并且每个环境只加载自己的环境配置即可,不需要加载所有环境的配置。
2. 基本思想
利用现有的公司的test环境,将项目的dev,beta和test环境配置都放在上面,即给不同的环境创建不同的namespace,如图
3. 实施步骤
- 在application.yml配置文件配置appid。
- 将beta、dev、release、test对应的配置文件的配置转移到apollo配置中心。
- 将beta、dev、release、test对应的配置文件的配置删除,分别加入配置:
apollo:
bootstrap:
enabled: true
# 当前环境对应的apollo中的namespace
namespaces: tiku-ziliao-dev.yml
# 当前环境对应的meta-server地址,该方案中,dev、test、beta环境均为http://test-apollo-meta.jarry.com,prod为http://apollo-meta.jarry.com
meta: http://test-apollo-meta.jarry.com
至此,引入完成!
4. 那些修改以后要重新加载bean的配置自动更新的处理
这类配置有mysql连接相关配置、redis连接相关配置、@ConfigurationProperties引入的配置等。
对于这种配置需要使用Apollo配置监听器,具体到该方案,需要不同环境监听不同的配置文件。
- @ApolloConfigChangeListener
该注解可以制指定要监听的namespace,但是不能实现根据不同的环境来监听不同的配置文件。
- Apollo原生API
该API可以根据指定的namespace获取其对用的Config对象,给Config对象添加事件监听即可,代码如下:
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
/**
* @author xujian03
* @date 2020/3/12 15:18
* @description
*/
@Component
@ConfigurationProperties(prefix = "my.user")
@RefreshScope
public class UserInfoConfig {
private String name;
private String nick;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNick() {
return nick;
}
public void setNick(String nick) {
this.nick = nick;
}
@Override
public String toString() {
return "UserInfoConfig{" +
"name='" + name + '\'' +
", nick='" + nick + '\'' +
'}';
}
}
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.scope.refresh.RefreshScope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.Set;
/**
* @author xujian03
* @date 2020/3/12 15:21
* @description
*/
@Component
public class SpringBootApolloRefreshConfig{
@Autowired
private UserInfoConfig userInfoConfig;
@Autowired
private RefreshScope refreshScope;
//指定的环境
@Value("${spring.profiles.active}")
private String env;
//配置文件前缀
private static final String NAMESPACE_PREFIX="xxx-";
//配置文件后缀
private static final String NAMESPACE_SUFFIX=".yml";
@PostConstruct
public void init() {
Config config = ConfigService.getConfig(NAMESPACE_PREFIX+env+NAMESPACE_SUFFIX);
Set<String> prefix = new HashSet<>();
prefix.add("my.user.");
//该方法有三个参数,第一个参数是具体的listener,第二个参数是感兴趣的key,第三个参数是感兴趣的key的前缀
config.addChangeListener(changeEvent -> {
System.out.println("before refresh "+userInfoConfig.toString());
//重新加载指定bean
refreshScope.refresh("userInfoConfig");
System.out.println("after refresh "+userInfoConfig.toString());
},null,prefix);
}
}
5. 注意事项
- spring.main.allow-bean-definition-overriding 这个配置放在apollo配置中心的时候不生效
解决方法:
1) 将spring.main.allow-bean-definition-overriding=true放到application.yml配置文件;
2) Apollo的客户端配置加上apollo.bootstrap.eagerLoad.enabled=true,如
apollo:
bootstrap:
enabled: true
# 当前环境对应的apollo中的namespace
namespaces: xxx.yml
# 让apollo配置更早加载
eagerLoad:
enabled: true
# 当前环境对应的meta-server地址
meta: http://test-apollo-meta.com
6. 后续改进
//配置文件前缀
private static final String NAMESPACE_PREFIX="tiku-ziliao-";
//配置文件后缀
private static final String NAMESPACE_SUFFIX=".yml";
这种前缀后缀可以放在配置文件里。
- 对于使用@ConfigurationProperties注解的bean,可以使用AOP自动加上listener。