简体   繁体   English

Spring Boot应用程序需要在@Configuration类中为使用@Value定义默认bean?

[英]Spring Boot application requires defining default beans in a @Configuration class for @Value to be used?

Recently, I have encountered a pretty strange situation. 最近,我遇到了一个非常奇怪的情况。

Please, consider a simple Spring Boot application: 请考虑一个简单的Spring Boot应用程序:

@SpringBootApplication
public class SampleApp implements WebMvcConfigurer {

    public static void main(String[] args) {
            SpringApplication.run(SampleApp.class, args);
    }
}

Inside this SampleApp, we do have a Configuration class such as: 在此SampleApp内,我们确实有一个Configuration类,例如:

@Configuration
public class Config {

    //Some @Bean definitions, but without things such as String
}

And then we do have some class: 然后我们有一些课程:

@Service
@RequiredArgsConstructor //Lombok
public class SomeService {

    @Value("${value.to.be.injected}")
    private final String someValue;
}

With the current state of things, the application refuses to launch: 在当前状态下,应用程序拒绝启动:

***************************
APPLICATION FAILED TO START
***************************
Description:

Parameter 0 of constructor in com.sampleapp required a bean of type 'java.lang.String' that could not be found.

Action:

Consider defining a bean of type 'java.lang.String' in your configuration.

However, should we define a @Bean in our configuration such as: 但是,我们应该在我们的配置中定义一个@Bean ,例如:

@Configuration
public class Config {

    @Bean
    public String string() {
        return new String();
    }
}

The application launches correctly, and even more, injects the value correctly. 该应用程序可以正确启动,甚至可以正确地注入值。 Why does that happen, and why does Spring act like this? 为什么会发生这种情况,为什么Spring会这样?

My guess is that you have added that "someValue" in the constructor and it tries to create the instance but cannot call the constructor without passing a value. 我的猜测是,您已在构造函数中添加了“ someValue”,它会尝试创建实例,但在不传递值的情况下无法调用构造函数。 That's why it breaks. 这就是为什么它会破裂。 Then if it finds a String value (a empty String bean which is matched as the only one that fits by the dependency injection) it uses it for the creation of the object and then sets the value because of the @Value annotation. 然后,如果找到一个String值(一个空的String bean,它被匹配为唯一的依赖项注入匹配),它将使用它来创建对象,然后由于@Value批注而设置该值。

You can try by removing the constructor of the bean (and @RequiredArgsConstructor) and it should work as expected because then all the properties will be injected using reflection and it will call the default no args constructor. 您可以尝试删除bean的构造函数(和@RequiredArgsConstructor),它应能按预期工作,因为所有属性将使用反射注入,并将调用默认的no args构造函数。

Another cool solution that would look nice and in a more "Spring" way would be to add the bean with the real value that you want to inject in the configuration and not have the @Value annotation - just use the constructor for initialization of the beans. 另一个不错的解决方案,以一种“ Spring”的方式看起来不错,它是使用您要在配置中注入的真实值添加Bean,并且没有@Value注释-只需使用构造函数来初始化Bean 。 Currently you are mixing it - part of the stuff comes from constructor and the other part is set later on. 当前,您正在混合它-一部分内容来自构造函数,另一部分则稍后设置。

And probably the best way (Which I should have written first maybe) is to add that value annotation to the constructor field. 最好的方法(可能应该是我应该写的最好的方法)是将该值注释添加到构造函数字段中。 Then it will use the value instead of searching for a bean. 然后它将使用该值而不是搜索bean。

@Service
@RequiredArgsConstructor //Lombok
public class SomeService {

   private final String someValue;
   public SomeService(@Value("${value.to.be.injected}") String someValue, other stuff....) { 
     this.someValue=someValue;
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM