Подтвердить что ты не робот

Добавить 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);
}
4b9b3361

Ответ 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)

Ответ 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);