从日志来看,配置项存在,也排除了拼写错误,但是启动工程时抛Failed to bind properties错误。
Reason: Failed to bind properties under 'module-name.search-service' to a.b.SearchServiceProperties$$EnhancerBySpringCGLIB$$fd93c720
跟了源码,发现在JavaBeanBinder
里的方法, 实现从property到bean的绑定(也就是给property赋值)。
private <T> boolean bind(BeanSupplier<T> beanSupplier, DataObjectPropertyBinder propertyBinder,
BeanProperty property) {
String propertyName = property.getName();
ResolvableType type = property.getType();
Supplier<Object> value = property.getValue(beanSupplier);
Annotation[] annotations = property.getAnnotations();
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;
}
下面方法的bean.getProperties
的值对应的是setter方法,而非属性。
private <T> boolean bind(DataObjectPropertyBinder propertyBinder, Bean<T> bean, BeanSupplier<T> beanSupplier,
Context context) {
boolean bound = false;
for (BeanProperty beanProperty : bean.getProperties().values()) {
bound |= bind(beanSupplier, propertyBinder, beanProperty);
context.clearConfigurationProperty();
}
return bound;
}
因此,如果有setter方法,但是没有对应的属性,在ResolvableType
里会是Void
,而Void
类型是不知道该怎么映射的,所以会报IllegalArgument
的错误。这个错误被捕获,重新包装成ConfigurationPropertiesBindException
抛出。于是就看到了上面的错误。
具体到这次的坑,就是下面的方法,isValid,被认为是有一个valid配置,因为方法没有属性,所以对应到Void。
@Configuration
@ConfigurationProperties(prefix = "module-name.search-service")
@Data
@RefreshScope
@Slf4j
public class SearchServiceProperties {
void isValid() { }
}
解决方法是:
- 所有的Setter方法都必须有参数
- 如果想要定义方法,要避免使用setter的名字,比如isXXX或者setXXX
因此改成这样就可以了:
public class SearchServiceProperties {
void isValid(Boolean valid) { }
void check() {}
}