为什么 spring 框架不将我的 YAML 列表绑定到实体?

Why doesn't spring framework bind my YAML list to an entity?

我正在尝试使用 @ConfigurationProperties 注释将对象列表绑定到我的实体 class。 Spring 引导框架似乎忽略了该注释,实际上什么也不做。

这是我的 application.yml 属性文件:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/search-engine
    username: landsreyk
    password: 12345678
  jpa:
    database-platform: org.hibernate.dialect.MySQLDialect
    show-sql: false
    hibernate:
      ddl-auto: none
sites:
  - url: http://someurl1.com
    name: somename1
  - url: https://someurl2.com
    name: somename2
  - url: https://someurl3.com
    name: somename3

这是我的实体 class:

package main.model;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import javax.persistence.*;
import java.sql.Timestamp;

@Getter
@Setter
@ToString
@Entity
@Table(name = "_site")
public class Site {
    @Column(nullable = false)
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Enumerated(EnumType.STRING)
    @Column(name = "status")
    private Status status;

    @Column(name = "status_time")
    private Timestamp statusTime;

    @Column(name = "last_error")
    private String lastError;

    private String url;

    private String name;

    public enum Status {
        INDEXING, INDEXED, FAILED
    }
}

绑定非常简单:

package main.utilities;

import lombok.Getter;
import lombok.Setter;
import main.model.Site;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.List;

@ConfigurationProperties
public class ApplicationProperties {

    @Getter
    @Setter
    private List<Site> sites;

}

我在应用程序的某处测试该绑定,假设我在我的 API 中创建了端点来测试该绑定,即我的控制器调用了一个方法,该方法仅打印列表中的所有对象:

package main.application.indexer;

import main.utilities.ApplicationProperties;
import org.springframework.beans.factory.annotation.Autowired;

public class IndexBuilder {
    @Autowired
    private ApplicationProperties properties;

    public void run() {
        System.out.println(properties.getSites());
    }

}

预期:

启动后,ApplicationProperties 实例不为空。调用 properties.getSites() returns 站点对象列表。每个 Site 对象都有 url 和从 yaml 源初始化的名称字段。

实际:

启动后 ApplicationProperties 实例为空。

我震惊地发现 Spring 无法完成如此简单的绑定。 知道仅解析 yaml 文件并不是一项艰巨的任务,我认为 Spring 框架应该内置此功能。 如何绑定我的列表?

顺便说一下,这是我的项目结构。

更新:

我编辑了 IndexBuilder class。添加了@Configuration 和@Bean 注解。 现在看起来像这样:

package main.application.indexer;

import main.utilities.ApplicationProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class IndexBuilder {
    @Autowired
    private ApplicationProperties properties;

    @Bean
    public void run() {
        System.out.println(properties.getSites());
    }

}

这解决了初始化问题,但是 Spring 框架在启动后立即调用 运行()。这不是预期的行为。

更新 2:

this 用户的回答是完全真实的。 他是对的。

事实证明,Spring并没有我想的那么聪明。

要访问@ConfigurationProperties class,即:从非管理对象访问 bean-spring class,- 我必须阅读这篇文章:

自动装配 Spring Beans 到 类 不受 Spring 管理 https://dzone.com/articles/autowiring-spring-beans-into-classes-not-managed-by-spring

问题解决了。

您应该在 IndexBuilder class.

上使用 @Component,而不是使用 @Configuration

@Configuration 应该只用于定义应用程序 beans 的配置 classes。这里实际上期望用 @Bean 注释的方法在应用程序启动时立即执行。这是 spring 创建所有需要的 bean 的阶段。但是我想知道 spring 接受带有 @Bean 注释的 void 方法。

您预计 运行 方法的执行时间是多少?使用普通的 bean/component/service 你可以在方法上使用 @PostConstruct 注释。然而,这些将在与 @Bean 方法相同的阶段执行,或者至少不会晚很多。