Spring 当使用验证器 Bean 时,引导自动装配配置仅为空
Spring Boot Autowired Configuration Only Null When Validator Bean Used
我有一个 Spring 引导配置 class,如下所示:
package foo.bar;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
@Configuration @ConfigurationProperties(prefix = "myConfig") public class MyConfig
{
private String foo;
private int myValue;
@NotNull private String requiredString;
@Min(0) @Max(100) private int smallPositiveInt;
public void setFoo(String foo) { this.foo = foo; }
public void setMyValue(int myValue) { this.myValue = myValue; }
public void setRequiredString(String requiredString) { this.requiredString = requiredString; }
public void setSmallPositiveInt(int smallPositiveInt)
{
this.smallPositiveInt = smallPositiveInt;
}
public String getRequiredString() { return requiredString; }
public int getSmallPositiveInt() { return smallPositiveInt; }
public String getFoo() { return foo; }
public int getMyValue() { return myValue; }
}
还有一个 YAML 配置文件,如下所示:
server:
port: 0
myConfig:
myValue: 9876543
foo: Goodbye
requiredString: Here
---
我的 Spring 应用程序代码如下所示:
package foo.bar;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication public class MyService implements ApplicationRunner
{
// Define the logger object for this class
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired private MyConfig myConfig;
// myConfig is null when I uncomment these lines:
// @Bean
// public Validator configurationPropertiesValidator()
// {
// return new MyConfigValidator();
// }
@Autowired ApplicationContext applicationContext;
@Override public void run(ApplicationArguments applicationArguments) throws Exception
{
log.info("Running application...");
log.info("MyConfig values:");
log.info("foo=" + myConfig.getFoo());
log.info("myValue=" + myConfig.getMyValue());
log.info("smallPositiveInt=" + myConfig.getSmallPositiveInt());
log.warn("Example warning log message.");
log.error("Example error log message.");
log.debug("Example debug log message.");
}
public static void main(String[] args) { SpringApplication.run(MyService.class, args); }
}
当我取消对验证器的注释时,自动装配的配置为空,但当它被注释掉时它工作正常。知道依赖注入会发生什么吗?
MyConfigValidator 现在完全空白,只是实现了没有实际功能的验证器,我可以 post 如果有人认为这可能是问题所在。
更新:
当我调试代码时,我可以看到 validate() 在 MyConfigValidator 中被调用,MyConfig 对象具有来自 YAML 文件的正确值。当它作为 Bean 包含在代码中时,Spring 是否有可能通过 Spring 引导应用程序将该对象注入到 MyConfigValidator 中?
更新二:
在查看 Spring Boot property validation example 之后,我能够通过创建一个实现 ApplicationRunner 的静态 class 来实现它。但是,我不明白为什么这是必要的,并且想避免这样做。
我认为 myConfig
为 null 的原因是 configurationPropertiesValidator
提前实例化了。这导致 MyService
在 AutowiredAnnotationBeanPostProcessor
可用于注入字段之前被实例化。
如果将 configurationPropertiesValidator()
方法设置为静态方法,应该可以正常工作:
@SpringBootApplication
public class MyService implements ApplicationRunner {
// ...
@Bean
public static Validator configurationPropertiesValidator() {
return new MyConfigValidator();
}
// ...
}
似乎最适合我的项目的方法是将验证器嵌入配置 class 中,如下所示:
@Component
@ConfigurationProperties(prefix = "myConfig")
public class MyConfig implements Validator
{
private String foo;
private int myValue;
private String requiredString;
private int smallPositiveInt;
private final Logger log = LoggerFactory.getLogger(this.getClass());
// This means that this validator only supports validating configs of type "MyConfig".
@Override public boolean supports(Class<?> type) { return type == MyConfig.class; }
@Override public void validate(Object o, Errors errors)
{
MyConfig c = (MyConfig)o;
log.info("Validating: " + c.toString());
if(c.getSmallPositiveInt() == 60)
{
errors.rejectValue("smallPositiveInt", "error", "Cannot be 60!");
}
}
}
请告诉我使用这种方法的任何缺点,它似乎是使用多个配置对象时的最佳解决方案,因为它们似乎在通过 Spring 依赖注入创建时得到验证。
我有一个 Spring 引导配置 class,如下所示:
package foo.bar;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
@Configuration @ConfigurationProperties(prefix = "myConfig") public class MyConfig
{
private String foo;
private int myValue;
@NotNull private String requiredString;
@Min(0) @Max(100) private int smallPositiveInt;
public void setFoo(String foo) { this.foo = foo; }
public void setMyValue(int myValue) { this.myValue = myValue; }
public void setRequiredString(String requiredString) { this.requiredString = requiredString; }
public void setSmallPositiveInt(int smallPositiveInt)
{
this.smallPositiveInt = smallPositiveInt;
}
public String getRequiredString() { return requiredString; }
public int getSmallPositiveInt() { return smallPositiveInt; }
public String getFoo() { return foo; }
public int getMyValue() { return myValue; }
}
还有一个 YAML 配置文件,如下所示:
server:
port: 0
myConfig:
myValue: 9876543
foo: Goodbye
requiredString: Here
---
我的 Spring 应用程序代码如下所示:
package foo.bar;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication public class MyService implements ApplicationRunner
{
// Define the logger object for this class
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired private MyConfig myConfig;
// myConfig is null when I uncomment these lines:
// @Bean
// public Validator configurationPropertiesValidator()
// {
// return new MyConfigValidator();
// }
@Autowired ApplicationContext applicationContext;
@Override public void run(ApplicationArguments applicationArguments) throws Exception
{
log.info("Running application...");
log.info("MyConfig values:");
log.info("foo=" + myConfig.getFoo());
log.info("myValue=" + myConfig.getMyValue());
log.info("smallPositiveInt=" + myConfig.getSmallPositiveInt());
log.warn("Example warning log message.");
log.error("Example error log message.");
log.debug("Example debug log message.");
}
public static void main(String[] args) { SpringApplication.run(MyService.class, args); }
}
当我取消对验证器的注释时,自动装配的配置为空,但当它被注释掉时它工作正常。知道依赖注入会发生什么吗?
MyConfigValidator 现在完全空白,只是实现了没有实际功能的验证器,我可以 post 如果有人认为这可能是问题所在。
更新: 当我调试代码时,我可以看到 validate() 在 MyConfigValidator 中被调用,MyConfig 对象具有来自 YAML 文件的正确值。当它作为 Bean 包含在代码中时,Spring 是否有可能通过 Spring 引导应用程序将该对象注入到 MyConfigValidator 中?
更新二: 在查看 Spring Boot property validation example 之后,我能够通过创建一个实现 ApplicationRunner 的静态 class 来实现它。但是,我不明白为什么这是必要的,并且想避免这样做。
我认为 myConfig
为 null 的原因是 configurationPropertiesValidator
提前实例化了。这导致 MyService
在 AutowiredAnnotationBeanPostProcessor
可用于注入字段之前被实例化。
如果将 configurationPropertiesValidator()
方法设置为静态方法,应该可以正常工作:
@SpringBootApplication
public class MyService implements ApplicationRunner {
// ...
@Bean
public static Validator configurationPropertiesValidator() {
return new MyConfigValidator();
}
// ...
}
似乎最适合我的项目的方法是将验证器嵌入配置 class 中,如下所示:
@Component
@ConfigurationProperties(prefix = "myConfig")
public class MyConfig implements Validator
{
private String foo;
private int myValue;
private String requiredString;
private int smallPositiveInt;
private final Logger log = LoggerFactory.getLogger(this.getClass());
// This means that this validator only supports validating configs of type "MyConfig".
@Override public boolean supports(Class<?> type) { return type == MyConfig.class; }
@Override public void validate(Object o, Errors errors)
{
MyConfig c = (MyConfig)o;
log.info("Validating: " + c.toString());
if(c.getSmallPositiveInt() == 60)
{
errors.rejectValue("smallPositiveInt", "error", "Cannot be 60!");
}
}
}
请告诉我使用这种方法的任何缺点,它似乎是使用多个配置对象时的最佳解决方案,因为它们似乎在通过 Spring 依赖注入创建时得到验证。