Добавить Bean Программно в Spring Контекст веб-приложения
Из-за архитектуры подключаемого модуля я пытаюсь добавить программный код bean в мой webapp. У меня есть Spring bean, созданный с помощью аннотации @Component
, и я реализую интерфейс ApplicationContextAware
.
Моя функция переопределения выглядит следующим образом:
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
// this fails
this.applicationContext = (GenericWebApplicationContext) applicationContext;
}
В принципе, я не могу понять, как добавить bean к объекту applicationContext, заданному для setApplicationContext. Может ли кто-нибудь сказать мне, как я это делаю неправильно?
Хорошо, это то, с чем я столкнулся, как решение:
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry bdr)
throws BeansException {
BeanDefinition definition = new RootBeanDefinition(
<My Class>.class);
bdr.registerBeanDefinition("<my id>", definition);
}
Ответы
Ответ 1
В Spring 3.0 вы можете реализовать bean BeanDefinitionRegistryPostProcessor
и добавить новый beans через BeanDefinitionRegistry
.
В предыдущих версиях Spring вы можете сделать то же самое в BeanFactoryPostProcessor
(хотя вам нужно отбрасывать BeanFactory
в BeanDefinitionRegistry
, что может закончиться неудачей).
Ответ 2
Вот простой код:
ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory();
beanFactory.registerSingleton(bean.getClass().getCanonicalName(), bean);
Ответ 3
Зачем вам нужно иметь тип GenericWebApplicationContext
?
Я думаю, что вы, вероятно, можете работать с любым типом ApplicationContext.
Обычно вы должны использовать метод init (в дополнение к вашему методу setter):
@PostConstruct
public void init(){
AutowireCapableBeanFactory bf = this.applicationContext
.getAutowireCapableBeanFactory();
// wire stuff here
}
И вы бы подключили beans к использованию
AutowireCapableBeanFactory.autowire(Class, int mode, boolean dependencyInject)
или
AutowireCapableBeanFactory.initializeBean(Object existingbean, String beanName)
Ответ 4
Ознакомьтесь с методами registerXXX (..) в JavaDoc. Пройдите учебник здесь
Ответ 5
Фактически AnnotationConfigApplicationContext
полученный из AbstractApplicationContext
, который имеет пустой метод postProcessBeanFactory
оставленный для переопределения
/**
* Modify the application context internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for registering special
* BeanPostProcessors etc in certain ApplicationContext implementations.
* @param beanFactory the bean factory used by the application context
*/
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}
Чтобы использовать это, создайте класс AnnotationConfigApplicationContextProvider
который может выглядеть следующим образом (данный Vertx
экземпляра Vertx
, вы можете использовать MyClass
)...
public class CustomAnnotationApplicationContextProvider {
private final Vertx vertx;
public CustomAnnotationApplicationContextProvider(Vertx vertx) {
this.vertx = vertx;
}
/**
* Register all beans to spring bean factory
*
* @param beanFactory, spring bean factory to register your instances
*/
private void configureBeans(ConfigurableListableBeanFactory beanFactory) {
beanFactory.registerSingleton("vertx", vertx);
}
/**
* Proxy method to create {@link AnnotationConfigApplicationContext} instance with no params
*
* @return {@link AnnotationConfigApplicationContext} instance
*/
public AnnotationConfigApplicationContext get() {
return new AnnotationConfigApplicationContext() {
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.postProcessBeanFactory(beanFactory);
configureBeans(beanFactory);
}
};
}
/**
* Proxy method to call {@link AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(DefaultListableBeanFactory)} with our logic
*
* @param beanFactory bean factory for spring
* @return
* @see AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(DefaultListableBeanFactory)
*/
public AnnotationConfigApplicationContext get(DefaultListableBeanFactory beanFactory) {
return new AnnotationConfigApplicationContext(beanFactory) {
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.postProcessBeanFactory(beanFactory);
configureBeans(beanFactory);
}
};
}
/**
* Proxy method to call {@link AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(Class[])} with our logic
*
* @param annotatedClasses, set of annotated classes for spring
* @return
* @see AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(Class[])
*/
public AnnotationConfigApplicationContext get(Class<?>... annotatedClasses) {
return new AnnotationConfigApplicationContext(annotatedClasses) {
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.postProcessBeanFactory(beanFactory);
configureBeans(beanFactory);
}
};
}
/**
* proxy method to call {@link AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(String...)} with our logic
*
* @param basePackages set of base packages for spring
* @return
* @see AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(String...)
*/
public AnnotationConfigApplicationContext get(String... basePackages) {
return new AnnotationConfigApplicationContext(basePackages) {
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.postProcessBeanFactory(beanFactory);
configureBeans(beanFactory);
}
};
}
}
При создании ApplicationContext
вы можете создать его, используя
Vertx vertx = ...; // either create or for vertx, it'll be passed to main verticle
ApplicationContext context = new CustomAnnotationApplicationContextProvider(vertx).get(ApplicationSpringConfig.class);