SpringBoot中类配置@ConfigurationProperties注解如何避免属性获取不到值

结论:类配置@ConfigurationProperties注解属性能被设置值满足以下两个条件:
1、set 方法被Public修饰并且没有被Static、Abstract修饰
2、Class类型不能为Object和Class

错误事例代码
setName 被static 修饰无法获取到值

@Component
@ConfigurationProperties(prefix = "demo")
public class Global
{
    private static String name;

    public static String getName()
    {
        return name;
    }

    public static void setName(String name)
    {
        Global.name = name;
    }
}

# 相关配置
demo:
  # 名称
  name: test

分析SpringBoot源码

public class Binder {
    ......
	private Object bindBean(ConfigurationPropertyName name, Bindable<?> target,
			BindHandler handler, Context context, boolean allowRecursiveBinding) {
		if (containsNoDescendantOf(context.getSources(), name)
				|| isUnbindableBean(name, target, context)) {
			return null;
		}
		BeanPropertyBinder propertyBinder = (propertyName, propertyTarget) -> bind(
				name.append(propertyName), propertyTarget, handler, context, false);
		Class<?> type = target.getType().resolve(Object.class);
		if (!allowRecursiveBinding && context.hasBoundBean(type)) {
			return null;
		}
		return context.withBean(type, () -> {
            // b.bind 是JavaBeanBinder的bind方法
			Stream<?> boundBeans = BEAN_BINDERS.stream()
					.map((b) -> b.bind(name, target, context, propertyBinder));
			return boundBeans.filter(Objects::nonNull).findFirst().orElse(null);
		});
	}
    ......
}
class JavaBeanBinder implements BeanBinder {

	@Override
	public <T> T bind(ConfigurationPropertyName name, Bindable<T> target, Context context,
			BeanPropertyBinder propertyBinder) {
		boolean hasKnownBindableProperties = hasKnownBindableProperties(name, context);
        Bean<T> bean = Bean.get(target, hasKnownBindableProperties);
		if (bean == null) {
			return null;
		}
		BeanSupplier<T> beanSupplier = bean.getSupplier(target);
        // 循环设置bean.getProperties()中的属性值
		boolean bound = bind(propertyBinder, bean, beanSupplier);
		return (bound ? beanSupplier.get() : null);
	}
    ......
    private <T> boolean bind(BeanSupplier<T> beanSupplier,
			BeanPropertyBinder propertyBinder, BeanProperty property) {
        // 获取属性名称
		String propertyName = property.getName();
        // 获取属性类型
		ResolvableType type = property.getType();
        // 获取属性值
		Supplier<Object> value = property.getValue(beanSupplier);
        // 获取注解
		Annotation[] annotations = property.getAnnotations();
        // 这里涉及到lambda方法的引用(Binder类中的bind(ConfigurationPropertyName name, Bindable<T> target,BindHandler handler, Context context, boolean allowRecursiveBinding)的调用)
        // 获取yml配置的属性值
		Object bound = propertyBinder.bindProperty(propertyName,
				Bindable.of(type).withSuppliedValue(value).withAnnotations(annotations));
		if (bound == null) {
			return false;
		}
		if (property.isSettable()) {
            // 设置属性值
			property.setValue(beanSupplier, bound);
		}
		else if (value == null || !bound.equals(value.get())) {
			throw new IllegalStateException(
					"No setter found for property: " + property.getName());
		}
		return true;
	}
    
    @SuppressWarnings("unchecked")
    public static <T> Bean<T> get(Bindable<T> bindable, boolean canCallGetValue) {
        // 获取对应的配置类(这里是Global.class)
        Class<?> type = bindable.getType().resolve(Object.class);
        Supplier<T> value = bindable.getValue();
        T instance = null;
        if (canCallGetValue && value != null) {
            // 实例化对象
            instance = value.get();
            type = (instance != null) ? instance.getClass() : type;
        }
        if (instance == null && !isInstantiable(type)) {
            return null;
        }
        Bean<?> bean = Bean.cached;
        if (bean == null || !type.equals(bean.getType())) {
            bean = new Bean<>(bindable.getType(), type);
            cached = bean;
        }
        return (Bean<T>) bean;
    }
    
    private static class Bean<T> {
    	private void putProperties(Class<?> type) {
			while (type != null && !Object.class.equals(type)) {
				for (Method method : type.getDeclaredMethods()) {
					// 判断方法是否符合要求
                    if (isCandidate(method)) {
                        // 绑定的类属性。
						addMethod(method);
					}
				}
				for (Field field : type.getDeclaredFields()) {
                    // 设置field
					addField(field);
				}
				type = type.getSuperclass();
			}
		}
        
        private boolean isCandidate(Method method) {
            // 返回方法的修饰符(例如这里是9,相加得到的值(public:1+static:8)=9)
			int modifiers = method.getModifiers();
            // 判断是否包含Public、非Abstract、非static、非Object、非Class
            // 这里是关键当方法被static修饰时,就被判定为不符合要求的方法了被忽略掉了
			return Modifier.isPublic(modifiers) && !Modifier.isAbstract(modifiers)
					&& !Modifier.isStatic(modifiers)
					&& !Object.class.equals(method.getDeclaringClass())
					&& !Class.class.equals(method.getDeclaringClass());
		}
    }
	.....
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值