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

Spring 如何使用@Configuration的现有实例创建注释配置bean?,spring,dependency-injection,annotations,guice,Spring,Dependency Injection,Annotations,Guice,假设我们有一个简单的@配置: @Configuration public class FooBarConfiguration { @Bean public Foo createFoo() { return new FooImpl(); } @Bean @Autowired public Bar createBar(Foo foo) { return new BarImpl(foo); } } 此类可与A

假设我们有一个简单的
@配置

@Configuration
public class FooBarConfiguration {

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

    @Bean
    @Autowired
    public Bar createBar(Foo foo) {
        return new BarImpl(foo);
    }
}
此类可与
AnnotationConfigApplicationContext
一起使用,以生成
Foo
Bar
实例:

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和bar

现在假设我们已经有了一个
FooBarConfiguration
的实例,我们希望通过Spring用这个实例创建Foos和bar。有没有办法做到这一点

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


另外,使用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());

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

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

@Configuration 
public class FooBarConfiguration { 

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

    @Bean 
    public Bar createBar() { 
        return new BarImpl(createFoo()); 
    } 
} 
您仍然会得到一个完全初始化的
Foo
实例,因为对
createFoo()
的调用将被拦截

以下是我自己的变体:

    @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());

    }

然而,我不确定这是一种“好”还是“正式”的方式。

在春季,你基本上必须:

  • 强制您的foobar配置为 单身人士(不依赖国际奥委会 用于强制执行此操作的容器-例如。 使用枚举或其他方法实现 单件模式)

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

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


  • 您不需要
    createBar
    上的
    @Inject
    注释。对!以及Spring示例中的@Autowired。我对基于注释的配置相当陌生,我主要是一个老派的SpringXML配置专家为什么需要使用配置类的现有实例而不是新实例?也许还有另一种方法可以达到你的目标…@meriton:简短的回答是因为我试图将一些基于Guice的DI东西从Guice移植到Spring。一个较长的答案是,这种方法允许对bean创建过程进行更多的编程控制。这里有一个例子。假设您有一个创建HTTP服务器(如Jetty)的bean工厂,您所需要做的就是提供一个端口。您的应用程序希望在运行时决定此端口。比较“Guice方式”和“Spring方式”,Guice的维护级别配置似乎要优雅得多。我真的不明白为什么直接模拟在Guice中工作是不可能的。我对某些功能不起作用表示满意,但一般来说,“这里的实例带有注释类,使用它们创建应用程序上下文”必须是可能的。当使用基于java的配置时,不作为Spring的配置类子类工作。2.调用工厂bean的方法如何知道使用哪个工厂?如何让spring在工厂创建的配置中创建bean?