Spring中@ConfigurationProperties+@PropertySource注入值为null问题排查
问题描述
我尝试通过自定义配置文件password.properties配置Spring Bean,为避免给每个字段添加@Valid,同时使用@ConfigurationProperties(将属性值加载到字段)和@PropertySource(加载自定义配置文件),但所有字段值均为null。已生成Setter、Getter方法,也尝试添加无参和全参构造方法,问题仍未解决。
相关代码
配置类PasswordConfig
@Configuration @EnableConfigurationProperties @ConfigurationPropertiesScan @PropertySource("classpath:password.properties") @ConfigurationProperties @Setter @Validated @Log4j2 public class PasswordConfig { @Min(1) private Integer minLength; @Min(1) private Integer maxLength; @Min(1) private Integer characterDigitMin; @Min(1) private Integer characterLowercaseMin; @Min(1) private Integer characterUppercaseMin; @Min(1) private Integer characterSpecialMin; @Bean public PasswordValidator passwordValidator() throws IOException { log.debug("Password validator [LENGTH: {}-{}, NUMBERS: {}, LOWERCASE: {}, UPPERCASE: {}, SPECIAL: {}]", minLength, maxLength, characterDigitMin, characterLowercaseMin, characterUppercaseMin, characterSpecialMin ); return new PasswordValidator(List.of( new LengthRule(minLength, maxLength), new CharacterRule(EnglishCharacterData.Digit, characterDigitMin), new CharacterRule(EnglishCharacterData.LowerCase, characterLowercaseMin), new CharacterRule(EnglishCharacterData.UpperCase, characterUppercaseMin), new CharacterRule(EnglishCharacterData.Special, characterSpecialMin), new WhitespaceRule() )); } }
配置文件password.properties
length.max=15 length.min=5 character.digit.min=1 character.uppercase.min=1 character.lowercase.min=1 character.special.min=1
Spring主类ReportsApplication
@SpringBootApplication @ConfigurationPropertiesScan public class ReportsApplication { public static void main(String[] args) { SpringApplication.run(ReportsApplication.class, args); } }
错误日志
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'passwordValidator' defined in class path resource [reports/config/PasswordConfig.class]: Failed to instantiate [org.passay.PasswordValidator]: Factory method 'passwordValidator' threw exception with message: Cannot invoke "java.lang.Integer.intValue()" because the return value of "reports.config.PasswordConfig.getMinLength()" is null Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.passay.PasswordValidator]: Factory method 'passwordValidator' threw exception with message: Cannot invoke "java.lang.Integer.intValue()" because the return value of "reports.config.PasswordConfig.getMinLength()" is null Caused by: java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because the return value of "reports.config.PasswordConfig.getMinLength()" is null at reports.config.PasswordConfig.passwordValidator(PasswordConfig.java:52) ~[classes/:na] at reports.config.PasswordConfig$$SpringCGLIB$$0.CGLIB$passwordValidator$11(<generated>) ~[classes/:na] at reports.config.PasswordConfig$$SpringCGLIB$$2.invoke(<generated>) ~[classes/:na] at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) ~[spring-core-6.0.12.jar:6.0.12] at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) ~[spring-context-6.0.12.jar:6.0.12] at reports.config.PasswordConfig$$SpringCGLIB$$0.passwordValidator(<generated>) ~[classes/:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) ~[spring-aop-6.0.12.jar:6.0.12] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) ~[spring-aop-6.0.12.jar:6.0.12] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-6.0.12.jar:6.0.12] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) ~[spring-aop-6.0.12.jar:6.0.12] at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:141) ~[spring-context-6.0.12.jar:6.0.12] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.0.12.jar:6.0.12] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) ~[spring-aop-6.0.12.jar:6.0.12] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) ~[spring-aop-6.0.12.jar:6.0.12] at reports.config.PasswordConfig$$SpringCGLIB$$3.passwordValidator(<generated>) ~[classes/:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:139) ~[spring-beans-6.0.12.jar:6.0.12] ... 25 common frames omitted Process finished with exit code 0
已尝试的解决方法
- 添加
@NoArgsConstructor和@AllArgsConstructor注解(无效) - 在类上添加
@EnableConfigurationProperties注解(无效) - 在类上添加
@ConfigurationPropertiesScan注解(无效)
解决方案
问题根源在于属性绑定不匹配、配置类生命周期冲突,修改步骤如下:
- 拆分配置与Bean创建逻辑
将纯属性绑定类和Bean配置类分离,确保属性绑定完成后再初始化Bean:
纯属性类PasswordProperties
@ConfigurationProperties(prefix = "password") @Setter @Getter @Validated public class PasswordProperties { @Min(1) private Integer lengthMin; @Min(1) private Integer lengthMax; @Min(1) private Integer characterDigitMin; @Min(1) private Integer characterLowercaseMin; @Min(1) private Integer characterUppercaseMin; @Min(1) private Integer characterSpecialMin; }
Bean配置类PasswordConfig
@Configuration @EnableConfigurationProperties(PasswordProperties.class) @PropertySource("classpath:password.properties") @Log4j2 public class PasswordConfig { private final PasswordProperties passwordProperties; // 构造注入确保属性已完成绑定 public PasswordConfig(PasswordProperties passwordProperties) { this.passwordProperties = passwordProperties; } @Bean public PasswordValidator passwordValidator() { log.debug("Password validator [LENGTH: {}-{}, NUMBERS: {}, LOWERCASE: {}, UPPERCASE: {}, SPECIAL: {}]", passwordProperties.getLengthMin(), passwordProperties.getLengthMax(), passwordProperties.getCharacterDigitMin(), passwordProperties.getCharacterLowercaseMin(), passwordProperties.getCharacterUppercaseMin(), passwordProperties.getCharacterSpecialMin() ); return new PasswordValidator(List.of( new LengthRule(passwordProperties.getLengthMin(), passwordProperties.getLengthMax()), new CharacterRule(EnglishCharacterData.Digit, passwordProperties.getCharacterDigitMin()), new CharacterRule(EnglishCharacterData.LowerCase, passwordProperties.getCharacterLowercaseMin()), new CharacterRule(EnglishCharacterData.UpperCase, passwordProperties.getCharacterUppercaseMin()), new CharacterRule(EnglishCharacterData.Special, passwordProperties.getCharacterSpecialMin()), new WhitespaceRule() )); } }
- 调整配置文件属性前缀
修改password.properties,为所有属性添加统一前缀,匹配@ConfigurationProperties的prefix:
password.length.min=5 password.length.max=15 password.character.digit.min=1 password.character.uppercase.min=1 password.character.lowercase.min=1 password.character.special.min=1
- 确保主类扫描范围正确
主类的@ConfigurationPropertiesScan默认扫描当前包及子包,若PasswordProperties在其他包下,需指定扫描路径:
@SpringBootApplication @ConfigurationPropertiesScan("reports.config") public class ReportsApplication { public static void main(String[] args) { SpringApplication.run(ReportsApplication.class, args); } }
内容的提问来源于stack exchange,提问作者Victor Hugo Pongolino
相关产品推荐
相关产品推荐

