Добавление компонента Bean программным способом в контекст Spring Web App - PullRequest
49 голосов
/ 27 декабря 2010

Из-за архитектуры подключаемого модуля я пытаюсь программно добавить bean-компонент в мое веб-приложение.У меня есть бин Spring, созданный с помощью аннотации @Component, и я реализую интерфейс ApplicationContextAware.

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

@Override
public void setApplicationContext(ApplicationContext applicationContext)
        throws BeansException {

    // this fails
    this.applicationContext = (GenericWebApplicationContext) applicationContext;
 }

По сути, я могу 't выяснить, как добавить bean-компонент в объект applicationContext, заданный для setApplicationContext.Может кто-нибудь сказать мне, как я поступаю об этом неправильно?

Хорошо, это то, что я закончил как решение:

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry bdr)
        throws BeansException {
    BeanDefinition definition = new RootBeanDefinition(
            <My Class>.class);

    bdr.registerBeanDefinition("<my id>", definition);
}

Ответы [ 4 ]

39 голосов
/ 27 декабря 2010

В Spring 3.0 вы можете заставить ваш bean-компонент реализовывать BeanDefinitionRegistryPostProcessor и добавлять новые bean-компоненты с помощью BeanDefinitionRegistry.

В предыдущих версиях Spring вы могли делать то же самое в BeanFactoryPostProcessor (хотя вам нужно привести BeanFactory к BeanDefinitionRegistry, что может привести к ошибке).

34 голосов
/ 15 мая 2014

Вот простой код:

ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory();
beanFactory.registerSingleton(bean.getClass().getCanonicalName(), bean);
9 голосов
/ 27 декабря 2010

Зачем вам нужно, чтобы он был типа GenericWebApplicationContext?
Я думаю, что вы, вероятно, можете работать с любым типом ApplicationContext.

Обычно вы используете метод init (в дополнение к вашему методу установки):

@PostConstruct
public void init(){
    AutowireCapableBeanFactory bf = this.applicationContext
        .getAutowireCapableBeanFactory();
    // wire stuff here
}

И вы могли бы связать бобы, используя либо

AutowireCapableBeanFactory.autowire(Class, int mode, boolean dependencyInject)

или

AutowireCapableBeanFactory.initializeBean(Object existingbean, String beanName)

1 голос
/ 11 апреля 2018

Фактически AnnotationConfigApplicationContext получено из AbstractApplicationContext, у которого есть пустой postProcessBeanFactory метод, оставленный для переопределения

/**
 * Modify the application context's 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 вместо него можно использовать 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);
...