Как создать bean-компоненты, настроенные для аннотаций, с существующим экземпляром @Configuration? - PullRequest
4 голосов
/ 15 июля 2010

Предположим, у нас есть простое @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 и использует его для создания Foos и Bars.

Теперь предположим, что у нас уже есть экземпляр из FooBarConfiguration, и мы хотим создать Foos и Bars через Spring с этим самым экземпляром . Есть ли способ сделать это?

Как создать настроенные аннотации 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());

Ответы [ 3 ]

2 голосов
/ 18 июля 2010

Вот мой собственный вариант:

    @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 голосов
/ 15 июля 2010

Это невозможно, потому что некоторые функции Spring @Configuration требуют улучшения класса, чего нельзя сделать в существующем экземпляре.

Например, вы можете переписать свою конфигурацию следующим образом:

@Configuration 
public class FooBarConfiguration { 

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

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

, и вы все равно получите полностью инициализированный экземпляр Foo, потому что вызов createFoo() будет перехвачен,

0 голосов
/ 23 июля 2010

Весной вам, в основном, нужно:

  1. Принудительно настроить FooBarConfiguration на Singleton (не полагаясь на контейнер IoC для принудительного выполнения этого - например, реализовать с использованием enum или другого шаблона Singleton).)

  2. Оберните свою конфигурацию FooBarConfiguration в FooBarConfigurationFactory и используйте для вызова что-то вроде MethodInvokingFactoryBean.

  3. Предоставьте статический метод фабрики непосредственно в FooBarConfiguration,и используйте ту же технику, что и # 2.

...