为什么 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
方法相同的阶段执行,或者至少不会晚很多。
我正在尝试使用 @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
方法相同的阶段执行,或者至少不会晚很多。