1. BeanPostProcessor を通じて @Value アノテーションが付けられた Bean を取得し、マップに格納します
2. Bean を動的に変更しますmap フィールドの値
まず、BeanPostProcessor インターフェースを実装するクラスを作成します。使用する必要があるのは、その関数の 1 つだけです。これは前後の両方で実装でき、必要なのは 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 をすでに取得し、マップに格納しています。テストを見てみましょう。コード
/** * 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 MethodParameter methodParameter; private Field field; private WeakReference<Object> beanRef; private String beanName; private String key; private String placeholder; private Class<?> targetType; private Type genericType; private boolean isJson; public SpringValue(String key, String placeholder, Object bean, String beanName, Field field, boolean isJson) { this.beanRef = new WeakReference<>(bean); this.beanName = beanName; this.field = field; this.key = key; this.placeholder = placeholder; this.targetType = field.getType(); this.isJson = isJson; if (isJson) { this.genericType = field.getGenericType(); } } public SpringValue(String key, String placeholder, Object bean, String beanName, Method method, boolean isJson) { this.beanRef = new WeakReference<>(bean); this.beanName = beanName; this.methodParameter = new MethodParameter(method, 0); this.key = key; this.placeholder = placeholder; Class<?>[] paramTps = method.getParameterTypes(); this.targetType = paramTps[0]; this.isJson = isJson; if (isJson) { this.genericType = method.getGenericParameterTypes()[0]; } } 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); } private void injectMethod(Object newVal) throws InvocationTargetException, IllegalAccessException { Object bean = beanRef.get(); if (bean == null) { return; } methodParameter.getMethod().invoke(bean, newVal); } public String getBeanName() { return beanName; } public Class<?> getTargetType() { return targetType; } public String getPlaceholder() { return this.placeholder; } public MethodParameter getMethodParameter() { return methodParameter; } public boolean isField() { return this.field != null; } public Field getField() { return field; } public Type getGenericType() { return genericType; } public boolean isJson() { return isJson; } boolean isTargetBeanValid() { return beanRef.get() != null; } @Override public String toString() { Object bean = beanRef.get(); if (bean == null) { return ""; } if (isField()) { return String .format("key: %s, beanName: %s, field: %s.%s", key, beanName, bean.getClass().getName(), field.getName()); } return String.format("key: %s, beanName: %s, method: %s.%s", key, beanName, bean.getClass().getName(), methodParameter.getMethod().getName()); } }
以上がSpringBoot2の動的@Valueを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。