【问题标题】:How to create annotation-configured beans with an existing instance of @Configuration?如何使用@Configuration 的现有实例创建注解配置的bean?
【发布时间】:2011-03-16 02:09:57
【问题描述】:

假设我们有一个简单的@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。

现在假设我们已经有一个FooBarConfigurationinstance,并且我们想通过 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());

【问题讨论】:

  • 你不需要createBar上的@Inject注解。
  • 对!以及 Spring 示例中的 @Autowired。我对基于注释的配置相当陌生,我主要是一个顽固的老派 Spring XML 配置专家。 :)
  • 为什么需要使用配置类的现有实例而不是新实例?也许还有另一种方法可以实现您的目标...
  • @meriton:简短的回答是因为我试图将一些基于 Guice 的 DI 东西从 Guice 移植到 Spring。一个更长的答案是,这种方法允许对 bean 创建过程进行更多的编程控制。这是一个例子。假设您有一个创建 HTTP 服务器(如 Jetty)的 bean 工厂,您需要做的就是提供一个端口。并且您的应用程序希望在运行时决定此端口。比较“Guice 方式”和“Spring 方式”——Guice 实例级配置似乎更加优雅。

标签: spring dependency-injection annotations guice


【解决方案1】:

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

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

@Configuration 
public class FooBarConfiguration { 

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

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

您仍然会得到一个完全初始化的Foo 实例,因为对createFoo() 的调用将被拦截。

【讨论】:

  • 我真的不明白为什么直接模拟在 Guice 中工作是不可能的。我对某些功能不起作用很好,但是一般的事情“这里是带有注释类的实例,用它们制作应用程序上下文”必须是可能的。
【解决方案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());

    }

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

【讨论】:

    【解决方案3】:

    在春季,您基本上必须:

    1. 强制您的 FooBarConfiguration 为 一个单例(不依赖于 IoC 强制执行此操作的容器 - 例如 使用枚举或其他实现 单例模式)

    2. 将 FooBarConfiguration 包装在 FooBarConfigurationFactory 中,并使用 MethodInvokingFactoryBean 之类的东西来调用它。

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

    【讨论】:

    • 1.使用 java-based-config 时,Spring 将配置类作为子类不起作用。 2. 调用工厂 bean 的方法如何知道使用哪个工厂?你会如何让 spring 在工厂创建的 Config 中创建 bean?
    猜你喜欢
    • 2013-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多