我需要创建一个spring bean的多个实例(我们将其称为MainPrototypeBean),可以使用prototype范围来实现。它依赖于其他一些bean,并且每次创建主bean时我都想创建它们的新实例。但是,在某些bean之间存在共享的依赖关系,我们将其称为SharedPrototypeBean。如何在每个从属bean中注入相同的SharedPrototypeBean实例,同时还为每个MainPrototypeBean创建一个新实例?

我正在考虑实现自定义范围,但我希望找到一种更简洁的方法。使任何一个豆成为单例都不是一种选择,因为它们需要在MainPrototypeBean的不同实例之间隔离。

这是我要执行的操作的一个示例:

@SpringBootApplication
public class DIDemo {
    public static void main(String[]args){
        ConfigurableApplicationContext context = SpringApplication.run(DIDemo.class, args);
        context.getBean(MainPrototypeBean.class);
    }

    @Component @Scope("prototype") static class SharedPrototypeBean {}

    @Component @Scope("prototype") static class FirstPrototypeBean {
        @Autowired SharedPrototypeBean shared;
        @PostConstruct public void init() {
            System.out.println("FirstPrototypeBean.init() with shared " + shared);
        }
    }

    @Component @Scope("prototype") static class SecondPrototypeBean {
        @Autowired SharedPrototypeBean shared;
        @PostConstruct public void init() {
            System.out.println("SecondPrototypeBean.init() with shared " + shared);
        }
    }

    @Component @Scope("prototype") static class MainPrototypeBean {
        @Autowired FirstPrototypeBean first;
        @Autowired SecondPrototypeBean second;
    }
}

执行它的输出是:
FirstPrototypeBean.init() with shared DIDemo$SharedPrototypeBean@1b84f475
SecondPrototypeBean.init() with shared DIDemo$SharedPrototypeBean@539d019

最佳答案

您可以将FactoryBean用于复杂的构造逻辑。实现其抽象子类AbstractFactoryBean来创建MainPrototypeBean,并将所有三个从属bean注入其中。然后,您可以使用createInstance方法将它们连接在一起。

FactoryBean实现:

public class MainFactoryBean extends AbstractFactoryBean<MainPrototypeBean> implements FactoryBean<MainPrototypeBean> {

private FirstPrototypeBean firstPrototype;
private SecondPrototypeBean secondPrototpye;
private SharedPrototypeBean sharedPrototype;

public MainFactoryBean(FirstPrototypeBean firstPrototype, SecondPrototypeBean secondPrototype, SharedPrototypeBean sharedPrototype) {
    this.firstPrototype = firstPrototype;
    this.secondPrototpye = secondPrototype;
    this.sharedPrototype = sharedPrototype;
}


@Override
protected MainPrototypeBean createInstance() throws Exception {
    MainPrototypeBean mainPrototype = new MainPrototypeBean();
    firstPrototype.setSharedPrototypeBean(sharedPrototype);
    secondPrototpye.setSharedPrototypeBean(sharedPrototype);
    mainPrototype.first = firstPrototype;
    mainPrototype.second = secondPrototpye;

    //call post construct methods on first and second prototype beans manually
    firstPrototype.init();
    secondPrototpye.init();
    return mainPrototype;
}

@Override
public Class<?> getObjectType() {
    return MainPrototypeBean.class;
}
}

注意:sharedPrototype在第一个和第二个原型的生命周期中的后构造阶段之后注入。因此,如果这些bean中有需要sharedPrototype的构造后逻辑,则在创建MainPrototypeBean时需要手动调用init方法。

您的注释-配置随之发生变化。不再自动连接sharedPrototype属性(它们在FactoryBean中设置),并且不再对MainPrototypeBean进行注释。相反,您需要创建MainFactoryBean
@Configuration
public class JavaConfig {

//method name is the name refers to MainPrototypeBean, not to the factory
@Bean
@Scope("prototype")
public MainFactoryBean mainPrototypeBean(FirstPrototypeBean firstPrototype, SecondPrototypeBean secondPrototype, SharedPrototypeBean sharedPrototype) {
    return new MainFactoryBean(firstPrototype, secondPrototype, sharedPrototype);
}
//Annotations are not needed anymore
static class MainPrototypeBean {
    FirstPrototypeBean first;
    SecondPrototypeBean second;
}

@Component
@Scope("prototype")
static class SharedPrototypeBean {
}

@Component
@Scope("prototype")
static class FirstPrototypeBean {
    private SharedPrototypeBean shared;
    //no autowiring required
    public void setSharedPrototypeBean(SharedPrototypeBean shared) {
        this.shared = shared;
    }
    @PostConstruct
    public void init() {//reference to shared will be null in post construction phase
        System.out.println("FirstPrototypeBean.init() with shared " + shared);
    }
}

@Component
@Scope("prototype")
static class SecondPrototypeBean {

    private SharedPrototypeBean shared;
    public void setSharedPrototypeBean(SharedPrototypeBean shared) {
        this.shared = shared;
    }

    @PostConstruct
    public void init() {
        System.out.println("SecondPrototypeBean.init() with shared " + shared);
    }
}
}

关于java - 在 Spring 共享原型(prototype) bean ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46564630/

10-10 17:08