【问题标题】:Loading properties using @Value into a BeanFactory object using @Bean in Spring Boot在 Spring Boot 中使用 @Bean 将使用 @Value 的属性加载到 BeanFactory 对象中
【发布时间】:2014-01-27 15:03:30
【问题描述】:

谁能帮我解决 Spring Boot 问题?

我想创建一个工厂 bean 作为我的应用程序上下文的一部分,但我希望能够使用注入的属性值来实例化它。但是,Spring 似乎会先加载 FactoryBeans,如下所示:

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.beans.factory.config.ListFactoryBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;

@EnableAutoConfiguration
public class TestClass
{
    @Value("${test.value}")
    String value;

    @Bean
    public Object test1()
    {
        System.out.println("test.value=" + value );

        List<String> list = new ArrayList<String>();
        ListFactoryBean factory = new ListFactoryBean();
        factory.setSourceList(list);

        return factory;
    }

    public static void main(String[] args)
    {
        SpringApplication.run(TestClass.class, args);
    }
}

当使用

运行时
java -Dtest.value=HELLO -jar myTest.jar

它正确加载了值:

test.value=HELLO

但是,当我指定要加载的 bean 实际上是一个工厂 bean,并以相同的方式运行它时:

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.beans.factory.config.ListFactoryBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;

@EnableAutoConfiguration
public class TestClass
{
    @Value("${test.value}")
    String value;

    @Bean
    public AbstractFactoryBean test1()
    {
        System.out.println("test.value=" + value );

        List<String> list = new ArrayList<String>();
        ListFactoryBean factory = new ListFactoryBean();
        factory.setSourceList(list);

        return factory;
    }

    public static void main(String[] args)
    {
        SpringApplication.run(TestClass.class, args);
    }
}

该值为空,因为它还没有被注入。

test.value=null

有没有办法解决这个问题?

谢谢

【问题讨论】:

    标签: spring


    【解决方案1】:

    Spring 通常必须查询 bean 定义以了解它们生成的对象类型。工厂 bean 总是有问题的,因为它们会导致依赖级联,徒劳地尝试在请求类型之前解析所有可用的动态信息。

    我认为ListFactoryBean 对其产品类型不够精确(getObjectType() 只能返回非通用List.class)。您也许可以编写自己的工厂,该工厂使用正确的泛型类型进行参数化。或者,您可能只需声明 @Bean 即可返回 FactoryBean&lt;List&lt;String&gt;

    另一个技巧是将@Bean 定义移动到一个单独的类(例如嵌套的静态类),以便它可以独立于应用程序上下文的其余部分进行实例化。例如

    @EnableAutoConfiguration
    public class TestClass
    {
    
      protected static class NestedConfiguration {
    
        @Value("${test.value}")
        String value;
    
        @Bean
        public FactoryBean<Properties> test1()
        {
            System.out.println("test.value=" + value );
            // ...
            return factory;
        }
    
      }
        ...
    
    }
    

    这不是真正的引导问题,因此您可以考虑更改标签。

    【讨论】:

    • 关于标签的公平点。现在已经改了。 ListFactoryBean 仅用于演示首先加载工厂 bean。我使用的 FactoryBean 返回 Properties.class 作为对象类型。我尝试将@Bean 移动到嵌套的静态类,但它抱怨注释不能放在那里。你能举个例子吗?
    • 使用示例嵌套配置进行编辑。也许如果您在某个地方(例如 github)可以访问一个完整的简化项目,这将有助于了解您需要的真正核心?
    【解决方案2】:

    看看Empowering your apps with Spring Boot's property support

    Spring Boot Actuator中新增注解@EnableConfigurationProperties

    Spring 环境是一个名称-值对的集合,取自(按优先级递减的顺序)

    1) 命令行,

    2) 外部配置文件,

    3) 系统属性,

    4) 操作系统环境。

    还可以以 YAML 格式定义应用程序属性(外部配置)。

    【讨论】:

    • 是的,我使用了@EnableConfigurationProperties,但似乎它们没有在 FactoryBean 之前加载。因此,如果您尝试使用这些属性中的任何一个注入到 FactoryBean 中,则它们为 null,因为它们尚未加载
    猜你喜欢
    • 1970-01-01
    • 2019-02-10
    • 2020-08-25
    • 2018-08-12
    • 1970-01-01
    • 2020-05-03
    • 1970-01-01
    • 2014-12-21
    • 2018-10-15
    相关资源
    最近更新 更多