Как я могу вставить bean в ApplicationContext перед загрузкой из файла?

У меня есть FileSystemXmlApplicationContext, и я хотел бы, чтобы beans, определенный в XML, принимал в качестве аргумента конструктора a bean, который не объявлен в Spring

Например, я хотел бы сделать:

<bean class="some.MyClass">
    <constructor-arg ref="myBean" />
</bean>

Итак, я мог представить, как это делается через что-то вроде:

Object myBean = ...
context = new FileSystemXmlApplicationContext(xmlFile);
context.addBean("myBean", myBean); //add myBean before processing
context.refresh();

За исключением того, что такого метода нет:-( Кто-нибудь знает, как я могу это достичь?

Ответ 1

Как о программном создании пустого родительского контекста, зарегистрировав ваш объект как одноэлемент с этим контекстом BeanFactory, используя тот факт, что getBeanFactory возвращает реализацию SingletonBeanRegistry.

parentContext = new ClassPathXmlApplicationContext();
parentContext.refresh(); //THIS IS REQUIRED
parentContext.getBeanFactory().registerSingleton("myBean", myBean)

Затем укажите этот контекст как родительский для вашего "реального" контекста. beans в дочернем контексте будет иметь возможность ссылаться на bean в родительском.

String[] fs = new String[] { "/path/to/myfile.xml" } 
appContext = new FileSystemXmlApplicationContext(fs, parentContext);

Ответ 2

Поскольку мне удалось решить эту проблему с помощью AnnotationConfigApplicationContext, я нашел следующую альтернативу:

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("customBean", new CustomBean());
context = new AnnotationConfigApplicationContext(beanFactory);
context.register(ContextConfiguration.class);
context.refresh();

Ответ 3

Если существующий контекст нуждается в бине, который вы хотите внедрить, то все должно быть сделано немного по-другому. Подходы в других ответах не работают по следующим причинам

  • Контекст не может быть обновлен, пока не будет зарегистрирован отсутствующий компонент
  • refresh() вызывает уничтожение введенного компонента.

Эту проблему можно обойти, используя "постпроцессор фабрики бинов", это позволяет запускать код после загрузки контекста, но до его обновления.

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
applicationContext.setConfigLocation("/org/example/app-context.xml");
applicationContext.getBeanFactoryPostProcessors().add(new BeanFactoryPostProcessor() {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        beanFactory.registerSingleton("customBeanName", customBean);
    }
});
applicationContext.refresh();