结论:类配置@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());
}
}
.....
}