首页 > 解决方案 > 按需实例化 Spring bean,而不是在启动时

问题描述

Spring Boot 2.x 在这里。我目前在一个@Configuration类中定义了一堆 bean,如下所示:

@Configuration
public class SomeConfig {

    @Bean
    public Fizz fizz() { ... }

    @Bean
    public Buzz buzz() { ... }

}

通常,Spring 会启动这个类并在启动时实例化这些 bean 。但是,就我而言,我希望 Spring 在启动时跳过加载此类(并实例化它的 bean),而是以编程方式/按需执行,如下所示:

public void processRequest(SomeRequest request) {

    Fizz fizz = SpringAdhocLoader.load(SomeConfig.class, Fizz.class);
    Buzz buzz = SpringAdhocLoader.load(SomeConfig.class, Buzz.class);

    // use these two beans in this method somehow

}

我需要这样做有一个非常具体的原因,这超出了这个问题的范围。所以我真的很感激“是的,你可以做到,这就是如何...... ”或“不,这不能用 Spring 完成,这就是为什么...... ”,而不是回答/评论问我为什么我要做。相信我,我需要!

归根结底,我正在寻找一种方法来告诉 Spring在我的代码的另一部分特别希望创建它们之前不要实例化我的类中的所有 bean 。SomeConfig这可能吗?如果可以,怎么做?


更新

如果Fizz看起来像这样怎么办:

@Component
public class Foobar {
    ...
}

public class Fizz {

    @Autowired
    private Foobar foobar;

    ...
}

即使自动装配/注入依赖项,@Lazy注释是否SomeConfig 仍会阻止实例化?Fizz@Component

标签: javaspringspring-bootdependency-injection

解决方案


根据您的具体要求,有多种方法可以实现这一点:

  • 如果@Lazy每个人都应该使用相同的对象实例,自动调用销毁回调,并在第一次请求 bean 时创建对象,则使用此选项。

  • 如果该范围内的每个人都应该使用相同的对象实例,则使用较短的生命周期,@Scope例如“会话”或“请求”,则自动调用销毁回调,并在第一次请求时创建对象。

  • 如果@Scope("prototype")每个人都应该获得一个新的对象实例,并且您愿意手动调用任何销毁回调,则使用此选项。

在所有情况下,注入“裸”bean 将请求创建该 bean。您可以通过注入 aProvider来避免这种情况:

class Foo {
    @Inject Bar bar;  // requests the creation of bar
}

class Foo {
    @Inject Provider<Bar> barProvider; // does not cause the creation of bar

    void something() {
        Bar bar = barProvider.get(); // requests the creation of bar 
    }
}

推荐阅读