如何使用现有的@Configuration实例创建注释配置的bean?

时间:2010-07-14 20:49:10

标签: spring dependency-injection annotations guice

假设我们有一个简单的@Configuration

@Configuration
public class FooBarConfiguration {

    @Bean
    public Foo createFoo() {
        return new FooImpl();
    }

    @Bean
    @Autowired
    public Bar createBar(Foo foo) {
        return new BarImpl(foo);
    }
}

此类可与AnnotationConfigApplicationContext一起使用,以生成FooBar个实例:

final ApplicationContext applicationContext =
    new AnnotationConfigApplicationContext(FooBarConfiguration.class);

final Foo foo = applicationContext.getBean(Foo.class);
final Bar bar = applicationContext.getBean(Bar.class);
assertSame(foo, bar.getFoo());

在上面的示例中,Spring将创建一个FooBarConfiguration的新实例,并使用它来生成Foos和Bars。

现在假设我们已经有FooBarConfiguration实例,我们希望通过Spring创建Foos和Bars,并使用这个实例。有没有办法实现这个目标?

如何使用配置对象的现有实例创建注释配置的bean?


PS。使用Google Guice,解决方案很简单:

public class FooBarConfiguration implements Module {

    @Provides
    @Singleton
    public Foo createFoo() {
        return new FooImpl();
    }

    @Override
    public void configure(Binder binder) {
    }

    @Provides
    @Inject
    @Singleton
    public Bar createBar(Foo foo) {
        return new BarImpl(foo);
    }
}

final FooBarConfiguration fooBarConfiguration = ...; // Our instance

final Injector injector = Guice.createInjector(fooBarConfiguration);
final Foo foo = injector.getInstance(Foo.class);
final Bar bar = injector.getInstance(Bar.class);
assertSame(foo, bar.getFoo());

3 个答案:

答案 0 :(得分:2)

这是不可能的,因为Spring的@Configuration的某些功能需要类增强,而这在现有实例上是无法完成的。

例如,您可以按如下方式重写配置:

@Configuration 
public class FooBarConfiguration { 

    @Bean 
    public Foo createFoo() { 
        return new FooImpl(); 
    } 

    @Bean 
    public Bar createBar() { 
        return new BarImpl(createFoo()); 
    } 
} 

并且您仍然会获得Foo的完全初始化的实例,因为对createFoo()的调用将被截获。

答案 1 :(得分:2)

这是我自己的变体:

    @Test
    public void createFromConfigurationInstance() {

        final FooBarConfiguration fooBarConfiguration = new FooBarConfiguration();

        final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        final AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(
                beanFactory);

        annotatedBeanDefinitionReader.register(FooBarConfiguration.class);

        beanFactory.registerSingleton("fooBarConfiguration",
                fooBarConfiguration);

        final ConfigurableApplicationContext applicationContext = new GenericApplicationContext(
                beanFactory);

        applicationContext.refresh();

        final Foo foo = applicationContext.getBean(Foo.class);
        final Bar bar = applicationContext.getBean(Bar.class);
        assertSame(foo, bar.getFoo());

    }

但是,我不确定这是“好”还是“官方”的方式。

答案 2 :(得分:0)

在春天你基本上要么:

  1. 强制你的FooBarConfiguration 单身人士(不依赖于IoC 容器来强制执行此操作 - 例如 使用枚举或其他方法实现 单身人士模式)

  2. 将您的FooBarConfiguration包装在FooBarConfigurationFactory中,并使用类似MethodInvokingFactoryBean的方法来调用它。

  3. 直接在FooBarConfiguration上公开静态工厂方法,并使用与#2相同的技术。