从构造函数访问时,Spring Boot application.properties显示为未注册



这是我的代码:

@Component
@Configuration
@PropertySource("application.properties")
public class Program {
    @Value("${app.title}")
    private String appTitle;
    
    public Program() {
        System.out.println(appTitle);
    }
}

application.properties具有

app.title=The Program 

输出是null而不是The Program

那么,我错过了什么?我试过几个例子;没有一个奏效。

由于appTitle是一个自动连接的字段,因此在最初构造对象之后才会设置它。这就是为什么在您的示例中该值仍然为null的原因。该场景中的bean构建过程如下:

  1. 调用Program构造函数,创建一个新的Program实例
  2. 新建bean上的appTitle字段设置为${app.title}

理想的解决方案取决于您的目标。如果您确实需要构造函数中的值,可以将其作为自动连接的构造函数参数传入。该值将在构造函数中可用:

@Component
@Configuration
@PropertySource("application.properties")
public class Program {
    public Program(@Value("${app.title}") appTitle) {
        System.out.println(appTitle);
    }
}

如果您在构造函数本身中不需要它,但需要它来正确初始化bean,那么您也可以在对象构造之后但在它可用于其他地方之前使用@javax.annotation.PostConstruct注释来使用它:

@Component
@Configuration
@PropertySource("application.properties")
public class Program {
    @Value("${app.title}")
    private String appTitle;
    @PostConstruct
    public void printAppTitle() {
        System.out.println(appTitle);
    }
}

最后,如果你在构建时不需要价值,而是在bean的生命周期中需要它,那么你所拥有的就会起作用;它只是在构造函数本身的主体中不可用:

@Component
@Configuration
@PropertySource("application.properties")
public class Program {
    @Value("${app.title}")
    private String appTitle;
}

没有错,只是不要在构造函数中执行。。。

这个问题的其他答案是假设目标是创建一个在创建中使用给定属性的Spring托管bean而编写的。然而,根据您在另一个答案中的评论,您想要回答的问题似乎是如何在无参数构造函数中访问外部化属性(由@Value提供的属性(。这是基于您的期望,即Java控制反转(IoC(容器(如Spring(应该允许在无参数构造函数中访问外部化的属性(以及可能的其他依赖项(。在这种情况下,这个答案将解决在无参数构造函数中访问属性的特定问题。

虽然肯定有实现这一目标的方法,但没有一种是Spring框架的惯用用法。正如您所发现的,自动连接的字段(即使用setter注入初始化的字段(无法在构造函数中访问。

有两个部分可以解释为什么会这样。首先,为什么它以编程的方式工作?第二,为什么它是这样设计的?

Spring文档中基于setter的依赖项注入部分解决了第一个问题:

基于Setter的DI是通过容器在调用无参数构造函数或无参数static工厂方法实例化bean后调用bean上的Setter方法来实现的。

在这种情况下,这意味着首先使用无参数构造函数创建对象。其次,一旦构建了对象,就会在构建的bean上初始化appTitle。由于在构造对象之后才初始化字段,因此它在构造函数中的默认值为null

第二个问题是为什么Spring是这样设计的,而不是以某种方式访问构造函数中的属性。基于构造函数还是基于setter的DI?Spring文档中的侧边栏清楚地表明,在处理强制依赖关系时,构造函数参数实际上是惯用方法。

由于可以混合使用基于构造函数和基于setter的DI,因此使用构造函数作为强制依赖项,使用setter方法或配置方法作为可选依赖项是一条很好的经验法则。[…]

Spring团队通常提倡构造函数注入,因为它允许您将应用程序组件实现为不可变对象,并确保所需的依赖项不为空。此外,构造函数注入的组件总是以完全初始化的状态返回给客户端(调用(代码。[…]

Setter注入应该主要只用于可选的依赖项,这些依赖项可以在类中分配合理的默认值。[…]

构造对象所需的属性肯定会被归类为强制依赖项。因此,Spring的惯用用法是在构造函数中传递这个必需的值。

因此,总之,Spring框架不支持尝试在无参数构造函数中访问应用程序属性,事实上,这与建议使用的框架背道而驰。

相关内容

最新更新