在Java Spring中将一个bean的值设置为另一个bean
Posted
技术标签:
【中文标题】在Java Spring中将一个bean的值设置为另一个bean【英文标题】:Setting the value of one bean to be another bean in Java Spring 【发布时间】:2017-09-07 21:16:37 【问题描述】:Spring bean 配置有两个主要问题: 1. 当我从应用程序上下文中检索 bean 时,我通过属性文件读取的属性没有持久化。 2. 我无法弄清楚如何将 bean 的值设置为另一个 bean - 在下面的示例中,我试图将 Plan bean 的 Metric 属性设置为某个 bean。
我有两个小类,一个 Metric 和一个更大的 Plan:
@Component
public class Metric
@Value("$nameOfMetric")
String name;
@Value("$empID")
String empID;
@Value("$value:0.0")
Double value;
还有一个更大的 Plan 对象,它具有三个不同的 Metrics 作为属性:
public class Plan
public Metric hoursWorked;
public Metric monthlyDeals;
public Metric monthlyGoal;
...
我还有一个正在读取的属性文件:
nameOfMetric = Untitled Metric
empID = Unknown
hoursWorked = 120.0
monthlyDeals = 40.0
monthlyGoal = 100.0
我有没有办法为每个指标(hoursWorked、monthlyDeals、monthlyGoal)创建 bean,然后将这些 bean 中的每一个注入到 Plan bean 中?到目前为止,我已经尝试使用带有 @Configuration 注释的 PropertyConfig 类:
@Inject
private Environment environment;
private Metric injectMetric(String propertyName)
Metric metric = new Metric();
metric.setEmpID(environment.getProperty("empID"));
metric.setName(propertyName);
metric.setValue(Double.parseDouble(environment.getProperty(propertyName)));
System.out.println("Metric injected: " + metric.toString());
return metric;
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer()
return new PropertySourcesPlaceholderConfigurer();
@Bean(name = "hoursWorkedBean")
@Scope("prototype")
public Metric hoursWorked()
Metric metric = injectMetric("hoursWorked");
return metric;
但是当我尝试访问这个 bean 时,我在主应用程序中获得了默认值或 null 值,这表明这些属性没有持久化:
Metric hoursWorked = (Metric) ctx.getBean("hoursWorkedBean");
System.out.println(hoursWorked.getName()); // prints out "Untitled Metric", but should print out "hoursWorked"
【问题讨论】:
【参考方案1】:您可以在 Spring Boot 应用程序中使用 @ConfigurationProperties。
您可以在 Spring Boot 应用程序中进行以下配置:
resources/application.yml
metrics:
hoursWorked:
name: one
empID: 1
value: 1.23
monthlyDeals:
name: two
empID: 2
value: 2.34
monthlyGoal:
name: three
empID: 3
value: 3.45
Metric.java(不要忘记 getter/setter)
public class Metric
private String name;
private String empID;
private Double value;
public String getName()
return name;
public void setName(String name)
this.name = name;
public String getEmpID()
return empID;
public void setEmpID(String empID)
this.empID = empID;
public Double getValue()
return value;
public void setValue(Double value)
this.value = value;
@Override
public String toString()
return "Metric" +
"name='" + name + '\'' +
", empID='" + empID + '\'' +
", value=" + value +
'';
Metrics.java(定义指标名称/限定符/配置)
public class Metrics
public static final String HOURS_WORKED = "hoursWorked";
public static final String MONTHLY_DEALS = "monthlyDeals";
public static final String MONTHLY_GOAL = "monthlyGoal";
MetricsConfiguration.java(创建 bean 并从配置中初始化它们)
@Configuration
public class MetricsConfiguration
@Bean
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
@Qualifier(Metrics.HOURS_WORKED)
@ConfigurationProperties(prefix = "metrics." + Metrics.HOURS_WORKED)
public Metric hoursWorked()
return new Metric();
@Bean
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
@Qualifier(Metrics.MONTHLY_DEALS)
@ConfigurationProperties("metrics." + Metrics.MONTHLY_DEALS)
public Metric monthlyDeals()
return new Metric();
@Bean
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
@Qualifier(Metrics.MONTHLY_GOAL)
@ConfigurationProperties("metrics." + Metrics.MONTHLY_GOAL)
public Metric monthlyGoal()
return new Metric();
DemoRunner.java(用于测试代码的命令行运行程序)
@Component
public class DemoRunner implements CommandLineRunner
@Autowired
private List<Metric> allMetrics;
@Autowired
@Qualifier(Metrics.HOURS_WORKED)
private Metric hoursWorkedMetric;
@Autowired
@Qualifier(Metrics.MONTHLY_DEALS)
private Metric monthlyDealsMetric;
@Autowired
@Qualifier(Metrics.MONTHLY_GOAL)
private Metric monthlyGoalMetric;
@Override
public void run(String... args) throws Exception
System.out.println();
System.out.println("All metrics:");
allMetrics.stream().forEach(System.out::println);
System.out.println();
System.out.println("HOURS_WORKED metric: " + hoursWorkedMetric);
System.out.println("MONTHLY_DEALS metric: " + monthlyDealsMetric);
System.out.println("MONTHLY_GOAL metric: " + monthlyGoalMetric);
System.out.println();
DemoApplication.java(SpringBoot 应用程序初始化)
@SpringBootApplication
public class DemoApplication
public static void main(String[] args)
SpringApplication.run(DemoApplication.class, args);
【讨论】:
这太棒了。谢谢你。我最初阅读了您的答案,认为它太复杂了,并决定我自己再搞砸一些,几天后把我的豆子连接起来。我最终完全按照你的描述做了。一个后续问题 - MetricsConfiguration.java 文件似乎很冗长。有什么办法可以减少那里的一些重复注释吗?我还在 Spring 学习曲线上。 @YuChen 您可以将 bean 配置放入任意数量的配置类中,只要您使用@Configuration
注释它们即可。您还可以将项目作为地图加载到配置类中。因此有一个指标图。如果有兴趣将您的指标加载到地图中,请查看this answer。
@YuChen 如果您将指标作为地图加载,那么您将不需要@Qualifier
用于区分相同类型的bean - 指标。此外,您不需要在配置类中保留多个属性,并且您的代码将可扩展以支持任意数量的指标。【参考方案2】:
你需要自动连接你的指标
public class Plan
@Autowired
public Metric hoursWorked;
@Autowired
public Metric monthlyDeals;
@Autowired
public Metric monthlyGoal;
...
【讨论】:
谢谢阿梅尔。您是否可以更详细地了解此实现?例如,我使用@Value("#monthlyGoalBean") 将Metrices 标记为注释,其中monthlyGoalBean 是在我的PropertyConfig 类中实例化的bean。我是否无法像我试图做的那样使用通过 SPEL 引用的 bean 来设置一个组件中的属性值?以上是关于在Java Spring中将一个bean的值设置为另一个bean的主要内容,如果未能解决你的问题,请参考以下文章