基于Spring java的配置,在导入的配置中使用范围原型

时间:2014-11-19 00:33:14

标签: java spring

是否可以使用原型范围创建基于导入java的配置的bean?

我的意思是,如果我有以下示例代码:

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(
        SpringTopLevelConfig.class);

for (int i = 0; i < 2; i++) {
    System.out.println(applicationContext.getBean(Student.class));
}

哪里

public class Notebook {
    static int idCounter = 1;
    private final int id;

    @Override
    public String toString() {
        return "Notebook{" +
               "id=" + id +
               '}';
    }

    public Notebook() {
        id = idCounter++;
    }
}

public class Student {
    private final Notebook notebook;

    @Override
    public String toString() {
        return "Student{" +
               "notebook=" + notebook +
               '}';
    }

    public Student(Notebook notebook) {
        this.notebook = notebook;
    }
}

Spring Config是:

@Configuration
public class SpringTopLevelConfig {

    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    @Bean
    Notebook notebook(){
        return new Notebook();
    }

    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    @Bean
    Student student(){
        return new Student(notebook());
    }
}

正如所料,每个学生都有自己的笔记本:

Student{notebook=Notebook{id=1}}
Student{notebook=Notebook{id=2}}

但是,如果我尝试将配置分成多个类,我发现所有示例都建议使用@Autowire来完成此任务:

@Configuration
@Import(SpringConfigSecondLevel.class)
public class SpringTopLevelConfig {

    @Autowired
    Notebook notebook;

    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    @Bean
    Student student(){
        return new Student(notebook);
    }
}

@Configuration
public class SpringConfigSecondLevel {

    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    @Bean
    Notebook notebook(){
        return new Notebook();
    }
}

然而,现在学生最终共享一个笔记本,这不是我想要实现的行为。

Student{notebook=Notebook{id=1}}
Student{notebook=Notebook{id=1}}

是否有一种弹簧方式可以使用拆分配置类实现SCOPE_PROTOTYPE行为,还是需要创建一个NotebookFactory bean来防止学生在同一个笔记本上互相争斗?

3 个答案:

答案 0 :(得分:1)

这两个配置文件方法没有预期的结果,因为您在SpringTopLevelConfig类中自动装配笔记本。该笔记本实例将被创建一次,并从所有其他学生对象中使用,因为当您创建学生时,在学生构造函数中传递该笔记本实例而不是notebook()bean方法。您可以通过自动装配整个配置类来传递学生构造函数中的notebook()bean方法,以便您可以调用它:

@Configuration
@Import(SpringConfigSecondLevel.class)
public class SpringTopLevelConfig {


    @Autowired SpringConfigSecondLevel springConfigSecondLevel;

    @Scope("prototype")
    @Bean
    Student student(){
        return new Student(springConfigSecondLevel.notebook());
    }
}

@Configuration
public class SpringConfigSecondLevel {

    @Scope("prototype")
    @Bean
    Notebook notebook(){
        return new Notebook();
    }
}

答案 1 :(得分:1)

由于Notebook实例是@Autowired,因此在创建springTopLevelConfig单例bean时将创建一次。从弹簧调试级别日志

可以看出这一点
14:59:15.631 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'springTopLevelConfig'
14:59:15.631 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'springTopLevelConfig'
14:59:15.639 [main] DEBUG o.s.b.f.annotation.InjectionMetadata - Registered injected element on class [com.example.spring.prototype_level.SpringTopLevelConfig$$EnhancerBySpringCGLIB$$2fffb2e0]: AutowiredFieldElement for com.example.spring.prototype_level.Notebook com.example.spring.prototype_level.SpringTopLevelConfig.notebook
14:59:15.640 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'springTopLevelConfig' to allow for resolving potential circular references
14:59:15.673 [main] DEBUG o.s.b.f.annotation.InjectionMetadata - Processing injected method of bean 'springTopLevelConfig': AutowiredFieldElement for com.example.spring.prototype_level.Notebook com.example.spring.prototype_level.SpringTopLevelConfig.notebook
14:59:15.682 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'notebook'
14:59:15.682 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'com.example.spring.prototype_level.SpringConfigSecondLevel'
14:59:15.682 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'com.example.spring.prototype_level.SpringConfigSecondLevel'
14:59:15.684 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'com.example.spring.prototype_level.SpringConfigSecondLevel' to allow for resolving potential circular references
14:59:15.698 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'com.example.spring.prototype_level.SpringConfigSecondLevel'
14:59:15.731 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'notebook'
14:59:15.732 [main] DEBUG o.s.b.f.a.AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'springTopLevelConfig' to bean named 'notebook'
14:59:15.733 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'springTopLevelConfig'
14:59:15.733 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor'
14:59:15.733 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor'
14:59:15.733 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'com.example.spring.prototype_level.SpringConfigSecondLevel'
14:59:15.736 [main] DEBUG o.s.c.a.AnnotationConfigApplicationContext - Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor@391663bd]
14:59:15.736 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'
14:59:15.739 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemProperties]
14:59:15.739 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemEnvironment]
14:59:15.740 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source. Returning [null]
14:59:15.740 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'student'
14:59:15.740 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'springTopLevelConfig'
14:59:15.752 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'student'
Student{notebook=Notebook{id=1}}
14:59:15.753 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'student'
14:59:15.753 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'springTopLevelConfig'
14:59:15.753 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'student'
Student{notebook=Notebook{id=1}}

另一种方法是使用applicationContext注入Notebook实例,如下所示

@Configuration
@Import(SpringConfigSecondLevel.class)
public class SpringTopLevelConfig{

    @Autowired
    private ApplicationContext applicationContext;

    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    @Bean
    Student student(){
        return new Student(applicationContext.getBean(Notebook.class));
    }


}

现在,每次创建Student实例时,spring都会创建Notebook实例。春天记录也是这样说的

14:55:51.255 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'springTopLevelConfig'
14:55:51.255 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'springTopLevelConfig'
14:55:51.258 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'springTopLevelConfig' to allow for resolving potential circular references
14:55:51.284 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'springTopLevelConfig'
14:55:51.285 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor'
14:55:51.285 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor'
14:55:51.285 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'com.example.spring.prototype_level.SpringConfigSecondLevel'
14:55:51.285 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'com.example.spring.prototype_level.SpringConfigSecondLevel'
14:55:51.287 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'com.example.spring.prototype_level.SpringConfigSecondLevel' to allow for resolving potential circular references
14:55:51.292 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'com.example.spring.prototype_level.SpringConfigSecondLevel'
14:55:51.295 [main] DEBUG o.s.c.a.AnnotationConfigApplicationContext - Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor@1396a464]
14:55:51.297 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'
14:55:51.300 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemProperties]
14:55:51.301 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemEnvironment]
14:55:51.302 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source. Returning [null]
14:55:51.302 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'student'
14:55:51.305 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'springTopLevelConfig'
14:55:51.342 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'notebook'
14:55:51.342 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'com.example.spring.prototype_level.SpringConfigSecondLevel'
14:55:51.352 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'notebook'
14:55:51.354 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'student'
Student{notebook=Notebook{id=1}}
14:55:51.355 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'student'
14:55:51.355 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'springTopLevelConfig'
14:55:51.355 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'notebook'
14:55:51.355 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'com.example.spring.prototype_level.SpringConfigSecondLevel'
14:55:51.355 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'notebook'
14:55:51.355 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'student'
Student{notebook=Notebook{id=2}}

答案 2 :(得分:1)

其他人解释了为什么你的第一次尝试不起作用。我只建议一个不需要使用@Autowired字段的解决方案。

@Configuration
@Import(SpringConfigSecondLevel.class)
public class SpringTopLevelConfig {

    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    @Bean
    public Student student(Notebook notebook) {
        return new Student(notebook);
    }
}

如果只是添加类型Notebook的方法参数,Spring容器将自动为您提供新实例。