首页 > 解决方案 > Spring @Bean 方法可以返回实例字段吗?

问题描述

以下 Spring bean 声明似乎“按预期”运行和表现:

@Configuration
public class AppConfig {

    private final Foo foo;

    public AppConfig() {
        foo = new Foo();
    }

    @Bean
    public Foo foo() {
        return foo;
    }
}

其中“如预期”的意思是“没有明显错误”。

假设它Foo有一些复杂的生命周期(例如用 管理外部资源AutoCloseable),这是一个有效且合理的声明foo()吗?我能找到的所有示例,无论是官方的还是非官方的,都表明该foo实例应该在内部实例化foo(),而不是存储在字段中并从字段中检索。但是,我在任何文档中都找不到确切的信息表明这应该或不应该是安全的。

我能找到的最相关的文档是关于 Spring IoC bean 生命周期的,例如https://docs.spring.io/spring/docs/5.1.0.RELEASE/spring-framework-reference/core.html#beans-factory -范围。例如,在行之间读取一个singletonapplication作用域的 bean 将是有效的,因为当它不再有效时,应用程序不再存在。由于singleton是默认范围,因此上面的声明变得隐式有效。

即使有适当的范围,假设您引入了一个替代的、特定于配置文件的声明

@Bean("foo")
@Profile("!test")
public Foo realFoo() {
    return this.foo;
}

@Bean("foo")
@Profile("test")
public Foo testFoo() {
    return new TestFoo();
}

现在将this.foo始终被实例化,即使在激活test配置文件时也是如此?realFoo()如果是这样,即使该 bean 应该处于非活动状态,Spring 是否仍然管理's value?

这个问题不是Spring @Bean at method return already created bean的重复,这引出了问题,但该问题可能正确识别答案。

标签: javaspring

解决方案


如果将 Spring IoC 存储在现场,您将失去 Spring IoC 所提供的好处,甚至可能导致某些范围内的意外行为。

如果范围是singleton或者application因为它只会调用foo()一次,这将起作用。但是如果范围更改为protoptype(每次都创建一个新实例)。那么它可能会导致意外的行为。因为你存储foo在一个字段中,所以它仍然会表现为singleton,因为它总是指向同一个实例。

如果您在构造函数中启动类,它将始终启动,即使配置文件未处于活动状态。Spring 不能(也不应该)检测实例的启动位置。如果配置文件未激活,Spring IoC 将不会调用该方法。除了上面的解释之外,在方法本身中启动实例会更安全。


推荐阅读