代码之家  ›  专栏  ›  技术社区  ›  lexicore

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

  •  4
  • lexicore  · 技术社区  · 15 年前

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

    @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 用它来制作足球场和酒吧。

    现在假设我们已经有了 实例 属于 foobar配置 我们想在春天用 这个例子 . 有办法做到这一点吗?

    如何使用 现有实例 配置对象的?


    PS.使用谷歌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 回复  |  直到 15 年前
        1
  •  2
  •   axtavt    15 年前

    这是不可能的,因为春天的某些特征 @Configuration 需要类增强,这在现有实例上无法实现。

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

    @Configuration 
    public class FooBarConfiguration { 
    
        @Bean 
        public Foo createFoo() { 
            return new FooImpl(); 
        } 
    
        @Bean 
        public Bar createBar() { 
            return new BarImpl(createFoo()); 
        } 
    } 
    

    您仍然可以得到一个完全初始化的 Foo ,因为呼叫 createFoo() 将被拦截。

        2
  •  2
  •   lexicore    15 年前

    这是我自己的变体:

        @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
  •  0
  •   jayshao    15 年前

    在春天,你基本上必须:

    1. 强迫你的foobarconfiguration 单打(不依赖国际奥委会 用于强制执行此操作的容器-例如 使用枚举或其他方法实现 单子模式)

    2. 在foobarconfigurationFactory中包装您的foobarconfiguration,并使用诸如MethodInvokingFactory之类的方法来调用它。

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