简体   繁体   English

Spring中的共享原型bean

[英]Shared prototype beans in Spring

I need to create multiple instances of a spring bean (let's call it MainPrototypeBean ), which I can do with the prototype scope. 我需要创建一个spring bean的多个实例(让我们称之为MainPrototypeBean ),我可以使用prototype范围。 It depends on some other beans, and I want to create new instances of them each time the main bean is created. 它依赖于其他一些bean,我想在每次创建主bean时创建它们的新实例。 However, there is a shared dependency between some of the beans, let's call it SharedPrototypeBean . 但是,某些bean之间存在共享依赖关系,我们称之为SharedPrototypeBean How do I inject the same instance of SharedPrototypeBean in each of the dependent beans, while also creating a new instance for each MainPrototypeBean ? 如何在每个依赖bean中注入相同的SharedPrototypeBean实例,同时还为每个MainPrototypeBean创建一个新实例?

I'm looking into implementing a custom scope, but I'm hoping to find a cleaner way. 我正在考虑实现自定义范围,但我希望找到一种更清洁的方式。 Making any of the beans singletons is not an option, as they need to be isolated between different instances of MainPrototypeBean . 制作任何bean单例都不是一种选择,因为它们需要在MainPrototypeBean不同实例之间隔离。

Here's an example of what I'm trying to do: 这是我正在尝试做的一个例子:

@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;
    }
}

And the output of executing it is: 执行它的输出是:

FirstPrototypeBean.init() with shared DIDemo$SharedPrototypeBean@1b84f475
SecondPrototypeBean.init() with shared DIDemo$SharedPrototypeBean@539d019

You can use the FactoryBean for complex construction logic. 您可以将FactoryBean用于复杂的构造逻辑。 Implement its abstract subclass AbstractFactoryBean for creating a MainPrototypeBean , and inject all three dependent beans into it. 实现其抽象子类AbstractFactoryBean以创建MainPrototypeBean ,并将所有三个依赖bean注入其中。 You can then wire them together in the createInstance method. 然后,您可以在createInstance方法中将它们连接在一起。

The FactoryBean implementation: 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;
}
}

Note : sharedPrototype is injected after the post-construct phase in the lifecycle of the first and second prototype. 注意sharedPrototype是在第一个和第二个原型的生命周期中的后构建阶段之后注入的。 So, if you have post-construction logic in these beans that require the sharedPrototype , you need to manually call the init-method when creating the MainPrototypeBean . 因此,如果在这些需要sharedPrototype bean中有后构造逻辑,则需要在创建MainPrototypeBean时手动调用init方法。

Your annotation - configuration changes as as a consequence. 您的注释 - 配置随之发生变化。 The sharedPrototype attributes are no longer autowired (they are set inside FactoryBean), and MainPrototypeBean is not annotated anymore. sharedPrototype属性不再自动装配(它们在FactoryBean中设置),并且MainPrototypeBean不再被注释。 Instead you need to create the MainFactoryBean . 相反,您需要创建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);
    }
}
}

After reading the comments and the other answer, I realized that the design is indeed too complex. 在阅读了评论和其他答案后,我意识到设计确实太复杂了。 I made SharedPrototypeBean , FirstPrototypeBean and SecondPrototypeBean regular POJOs, not managed by Spring. 我创建了SharedPrototypeBeanFirstPrototypeBeanSecondPrototypeBean常规POJO,而不是由Spring管理。 I then create all of the objects in a @Bean annotated method. 然后我在@Bean注释方法中创建所有对象。

@Bean
public MainPrototypeBean mainPrototypeBean() {
    Shared shared = new Shared();
    First first = new First(shared);
    Second second = new Second(shared);
    return new MainPrototypeBean(first, second);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM