title: SpringBoot2.动态@Value实现
前言
前面文章有详细描述过各个不同阶段对于bean的扩展接口
所以今天就基于BeanPostProcessor实现Spring中的@Value注解值动态变化
基于上面也可以实现一个配置中心,比如说Apollo
具体的实现步骤分为如下几步
1.通过BeanPostProcessor取得有使用@Value注解的bean,并存储到map中
2.动态修改map中的bean字段的值
获取bean
首先写一个类实现BeanPostProcessor接口,只需要使用其中的一个函数就可以。前后都可以用来实现,并不影响最终的使用,因为咱们只是需要bean的实例。
接下来看一下具体实现代码
package com.allen.apollo;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@Configuration
public class SpringValueProcessor implements BeanPostProcessor {
private final PlaceholderHelper placeholderHelper = new PlaceholderHelper();
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("springValueController")) {
Class obj = bean.getClass();
List<Field> fields = findAllField(obj);
for (Field field : fields) {
Value value = field.getAnnotation(Value.class);
if (value != null) {
Set<String> keys = placeholderHelper.extractPlaceholderKeys(value.value());
for (String key : keys) {
SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, field, false);
SpringValueCacheMap.map.put(key, springValue);
}
}
}
}
return bean;
}
private List<Field> findAllField(Class clazz) {
final List<Field> res = new LinkedList<>();
ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
res.add(field);
}
});
return res;
}
}
上面的代码咱们就已经拿到了SpringValueController这个实例bean并存储到了map当中,下面看一下测试代码
/**
* cache field,存储bean 字段
*/
package com.allen.apollo;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap;
public class SpringValueCacheMap {
public static final Multimap<String, SpringValue> map = LinkedListMultimap.create();
}
package com.allen.apollo;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import org.springframework.core.MethodParameter;
public class SpringValue {
private MethodParame