使用 SpringBoot 的自动配置。
@Data
@Component
@ConfigurationProperties(prefix = "xxx")
private Boolean isSandbox = false;
配置文件中: xxxx.isSandbox =true
但是并没有生效。我虽然阅读spring源码,但是springBoot源码我没有读,所以我相信源码一定会带来答案。
@ConfigurationProperties(prefix = “xxx”)
像赋值这种事,应该是在bean实例化的时候做的,所以点开注释使用者应该去找XXXPostProcessor类,果然我找到了ConfigurationPropertiesBindingPostProcessor类,点开。
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
bind(ConfigurationPropertiesBean.get(this.applicationContext, bean, beanName));
return bean;
}
private void bind(ConfigurationPropertiesBean bean) {
if (bean == null || hasBoundValueObject(bean.getName())) {
return;
}
Assert.state(bean.getBindMethod() == BindMethod.JAVA_BEAN, "Cannot bind @ConfigurationProperties for bean '"
+ bean.getName() + "'. Ensure that @ConstructorBinding has not been applied to regular bean");
try {
this.binder.bind(bean);
}
catch (Exception ex) {
throw new ConfigurationPropertiesBindException(bean, ex);
}
}
发现bind 似乎就是我想知道的。
继续往下
BindResult<?> bind(ConfigurationPropertiesBean propertiesBean) {
Bindable<?> target = propertiesBean.asBindTarget();
ConfigurationProperties annotation = propertiesBean.getAnnotation();
BindHandler bindHandler = getBindHandler(target, annotation);
return getBinder().bind(annotation.prefix(), target, bindHandler);
}
这段代码应是获取 bindHandler,随后去绑定配置值。一路next
private <T> T bind(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler, boolean create) {
Assert.notNull(name, "Name must not be null");
Assert.notNull(target, "Target must not be null");
handler = (handler != null) ? handler : this.defaultBindHandler;
Context context = new Context();
return bind(name, target, handler, context, false, create);
}
private <T> T bind(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler, Context context,
boolean allowRecursiveBinding, boolean create) {
try {
Bindable<T> replacementTarget = handler.onStart(name, target, context);
if (replacementTarget == null) {
return handleBindResult(name, target, handler, context, null, create);
}
target = replacementTarget;
Object bound = bindObject(name, target, handler, context, allowRecursiveBinding);
return handleBindResult(name, target, handler, context, bound, create);
}
catch (Exception ex) {
return handleBindError(name, target, handler, context, ex);
}
}
一路next,发现正在遍历 dataObjectBinder 我们找到Binder构造方法,看看里面有没有定义这些dataObjectBinders
private Object bindDataObject(ConfigurationPropertyName name, Bindable<?> target, BindHandler handler,
Context context, boolean allowRecursiveBinding) {
if (isUnbindableBean(name, target, context)) {
return null;
}
Class<?> type = target.getType().resolve(Object.class);
if (!allowRecursiveBinding && context.isBindingDataObject(type)) {
return null;
}
DataObjectPropertyBinder propertyBinder = (propertyName, propertyTarget) -> bind(name.append(propertyName),
propertyTarget, handler, context, false, false);
return context.withDataObject(type, () -> {
for (DataObjectBinder dataObjectBinder : this.dataObjectBinders) {
Object instance = dataObjectBinder.bind(name, target, context, propertyBinder);
if (instance != null) {
return instance;
}
}
return null;
});
}
我们发现:
public Binder(Iterable<ConfigurationPropertySource> sources, PlaceholdersResolver placeholdersResolver,
List<ConversionService> conversionServices, Consumer<PropertyEditorRegistry> propertyEditorInitializer,
BindHandler defaultBindHandler, BindConstructorProvider constructorProvider) {
Assert.notNull(sources, "Sources must not be null");
for (ConfigurationPropertySource source : sources) {
Assert.notNull(source, "Sources must not contain null elements");
}
this.sources = sources;
this.placeholdersResolver = (placeholdersResolver != null) ? placeholdersResolver : PlaceholdersResolver.NONE;
this.bindConverter = BindConverter.get(conversionServices, propertyEditorInitializer);
this.defaultBindHandler = (defaultBindHandler != null) ? defaultBindHandler : BindHandler.DEFAULT;
if (constructorProvider == null) {
constructorProvider = BindConstructorProvider.DEFAULT;
}
ValueObjectBinder valueObjectBinder = new ValueObjectBinder(constructorProvider);
JavaBeanBinder javaBeanBinder = JavaBeanBinder.INSTANCE;
this.dataObjectBinders = Collections.unmodifiableList(Arrays.asList(valueObjectBinder, javaBeanBinder));
}
有两个Binder,一个是ValueObjectBinder 一个是JavaBeanBinder ,进去看看 bind 方法都做了什么
ValueObjectBinder 的
@Override
public <T> T bind(ConfigurationPropertyName name, Bindable<T> target, Binder.Context context,
DataObjectPropertyBinder propertyBinder) {
ValueObject<T> valueObject = ValueObject.get(target, this.constructorProvider, context);
if (valueObject == null) {
return null;
}
context.pushConstructorBoundTypes(target.getType().resolve());
List<ConstructorParameter> parameters = valueObject.getConstructorParameters();
List<Object> args = new ArrayList<>(parameters.size());
boolean bound = false;
for (ConstructorParameter parameter : parameters) {
Object arg = parameter.bind(propertyBinder);
bound = bound || arg != null;
arg = (arg != null) ? arg : getDefaultValue(context, parameter);
args.add(arg);
}
context.clearConfigurationProperty();
context.popConstructorBoundTypes();
return bound ? valueObject.instantiate(args) : null;
}
这大概的意思是有值就放没有就默认值的,我猜想这应该是 ${xxx} 这种赋值的。
所以我们应该去看给类赋值的
再Bind里一路next发现
protected void addProperties(Method[] declaredMethods, Field[] declaredFields) {
for (int i = 0; i < declaredMethods.length; i++) {
if (!isCandidate(declaredMethods[i])) {
declaredMethods[i] = null;
}
}
for (Method method : declaredMethods) {
addMethodIfPossible(method, "is", 0, BeanProperty::addGetter);
}
for (Method method : declaredMethods) {
addMethodIfPossible(method, "get", 0, BeanProperty::addGetter);
}
for (Method method : declaredMethods) {
addMethodIfPossible(method, "set", 1, BeanProperty::addSetter);
}
for (Field field : declaredFields) {
addField(field);
}
}
顿时一切都明白了,因为这个字段叫isSandbox ,他的方法也叫isSandbox ,如果想要它生效,把它换成大布尔类型,或者改名为setIsSandbox.]
2023/12/21 - 记录