一直很好奇spring生成的bean对象,apollo是如何修改其属性值的,比如通过 @Value注入的属性,而且还可以实时生效。 今来探究一番,只讲关键点,忽略很多细节。
前提条件,需要对spring创建bean对象过程和springboot启动有一定的了解。
GitHub地址:https://github.com/apolloconfig/apollo
IDEA搭建的源码环境如下:
我们的apollo服务搭建好之后,我们的应用会引入如下客户端依赖:
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.9.2</version>
</dependency>
我们要探索的就是这里。
主要有两种方式:基于java配置,springboot集成方式。
@Configuration
@EnableApolloConfig
public class AppConfig {
@Bean
public TestJavaConfigBean javaConfigBean() {
return new TestJavaConfigBean();
}
}
# will inject 'application' namespace in bootstrap phase
apollo.bootstrap.enabled = true
这里主要介绍springboot集成方式。
public class ConfigPropertySourcesProcessor extends PropertySourcesProcessor
implements BeanDefinitionRegistryPostProcessor {
// 这里创建helper对象,看这个对象的代码
private ConfigPropertySourcesProcessorHelper helper = ServiceBootstrap.loadPrimary(ConfigPropertySourcesProcessorHelper.class);
// 这里注册BeanDefinition到BeanFactory
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
helper.postProcessBeanDefinitionRegistry(registry);
}
}
ConfigPropertySourcesProcessorHelper的实现DefaultConfigPropertySourcesProcessorHelper
这里向BeanDefinitionRegistry注册SpringValueProcessor。
SpringValueProcessor类
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) {
// 看这个方法
super.postProcessBeforeInitialization(bean, beanName);
processBeanPropertyValues(bean, beanName);
}
return bean;
}
// 在父类ApolloProcessor实现
@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;
}
@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注册SpringValue
springValueRegistry.register(beanFactory, key, springValue);
logger.debug("Monitoring {}", springValue);
}
}
@Override
public void onChange(ConfigChangeEvent changeEvent) {
Set<String> keys = changeEvent.changedKeys();
if (CollectionUtils.isEmpty(keys)) {
return;
}
for (String key : keys) {
// 1. check whether the changed key is relevant
Collection<SpringValue> targetValues = springValueRegistry.get(beanFactory, key);
if (targetValues == null || targetValues.isEmpty()) {
continue;
}
// 2. update the value
for (SpringValue val : targetValues) {
// 改变值
updateSpringValue(val);
}
}
}
private void updateSpringValue(SpringValue springValue) {
try {
Object value = resolvePropertyValue(springValue);
springValue.update(value);
logger.info("Auto update apollo changed value successfully, new value: {}, {}", value,
springValue);
} catch (Throwable ex) {
logger.error("Auto update apollo changed value failed, {}", springValue.toString(), ex);
}
}
public void update(Object newVal) throws IllegalAccessException, InvocationTargetException {
if (isField()) {
injectField(newVal);
} else {
injectMethod(newVal);
}
}
private void injectField(Object newVal) throws IllegalAccessException {
Object bean = beanRef.get();
if (bean == null) {
return;
}
boolean accessible = field.isAccessible();
field.setAccessible(true);
// 通过反射方式改变值。
field.set(bean, newVal);
field.setAccessible(accessible);
}