背景
最近在使用apollo的时候,发现@Value注释的值,有部分能热更新,部分不能;对于ConfigurationProperties的配置类,完全不支持更新。所以想着了解一下apollo的热发布机制,看看是怎么实现的热发布。
官方介绍
从上面三个图可以看出:热更新,就是基于http长连接,当在apollo管理界面上修改配置时,会通知客户端有变更,然后客户端再去拉取最新的配置。
官方文档只是介绍了一下热更新机制,但是对于客户端拿到最新的配置后,怎么做到更新spring的bean的属性,却没提到。
SpringValueProcessor代码
com.ctrip.framework.apollo.spring.annotation目录下的类如下:
可以看到里面有一个SpringValueProcessor,从名字看,这个类的作用似乎是对spring中加了@Value注解的bean做处理的。
public class SpringValueProcessor extends ApolloProcessor implements BeanFactoryPostProcessor, BeanFactoryAware {
private static final Logger logger = LoggerFactory.getLogger(SpringValueProcessor.class);
private final ConfigUtil configUtil;
private final PlaceholderHelper placeholderHelper;
private final SpringValueRegistry springValueRegistry;
private BeanFactory beanFactory;
private Multimap<String, SpringValueDefinition> beanName2SpringValueDefinitions;
public SpringValueProcessor() {
configUtil = ApolloInjector.getInstance(ConfigUtil.class);
placeholderHelper = SpringInjector.getInstance(PlaceholderHelper.class);
springValueRegistry = SpringInjector.getInstance(SpringValueRegistry.class);
beanName2SpringValueDefinitions = LinkedListMultimap.create();
}
......
......
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) {
super.postProcessBeforeInitialization(bean, beanName);
processBeanPropertyValues(bean, beanName);
}
return bean;
}
@Override
protected void processField(Object bean, String beanName, Field field) {
// register @Value on field
Value value = field.getAnnotation(Value.class);
if (value == null) {
return;
}
Set<String> keys = placeholderHelper.extractPlaceholderKeys(value.value());
if (keys.isEmpty()) {
return;
}
for (String key : keys) {
SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, field, false);
springValueRegistry.register(beanFactory, key, springValue);
logger.debug("Monitoring {}", springValue);
}
}
@Override
protected void processMethod(Object bean, String beanName, Method method) {
//register @Value on method
Value value = method.getAnnotation(Value.class);
if (value == null) {
return;
}
//skip Configuration bean methods
if (method.getAnnotation(Bean.class) != null) {
return;
}
if (method.getParameterTypes().length != 1) {
logger.error("Ignore @Value setter {}.{}, expecting 1 parameter, actual {} parameters",
bean.getClass().getName(), method.getName(), method.getParameterTypes().length);
return;
}
Set<String> keys = placeholderHelper.extractPlaceholderKeys(value.value());
if (keys.isEmpty()) {
return;
}
for (String key : keys) {
SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, method, false);
springValueRegistry.register(beanFactory, key, springValue);
logger.info("Monitoring {}", springValue);
}
}
......
......
}
SpringValueProcessor.postProcessBeforeInitialization
SpringValueProcessor重要的是postProcessBeforeInitialization方法:
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
// 是否支持自动更新,不支持就啥事情都不做
if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) {
// 调用父类的postProcessBeforeInitialization
super.postProcessBeforeInitialization(bean, beanName);
// PropertyValues的一些处理,不需要关心
processBeanPropertyValues(bean, beanName);
}
return bean;
}
SpringValueProcessor.postProcessBeforeInitialization方法调用的是父类的postProcessBeforeInitialization方法,父类的方法内容如下:
public abstract class ApolloProcessor implements BeanPostProcessor, PriorityOrdered {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
Class clazz = bean.getClass();
for (Field field : findAllField(clazz)) {
processField(bean, beanName, field);
}
for (Method method : findAllMethod(clazz)) {
processMethod(bean, beanName, method);
}
return bean;
}
......
protected abstract void processField(Object bean, String beanName, Field field);
protected abstract void processMethod(Object bean, String beanName, Method method);
......
private List<Field>