【问题标题】:Setting the value of one bean to be another bean in Java Spring在Java Spring中将一个bean的值设置为另一个bean
【发布时间】: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"

【问题讨论】:

    标签: java spring spring-mvc


    【解决方案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 来设置一个组件中的属性值?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多