Add Bean Programmatically to Spring Web App Context

JavaSpringWeb ApplicationsDynamic

Java Problem Overview


Because of a plug-in architecture, I'm trying to add a bean programmatically to my webapp. I have a Spring bean created through the @Component annotation, and i am implementing the ApplicationContextAware interface.

My override function looks like this:

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

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

Basically, I can't figure out how to add a bean to the applicationContext object given to setApplicationContext. Can anyone tell me how I am going about this the wrong way?

Ok, this is what i ended up with as the solution:

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

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

Java Solutions


Solution 1 - Java

Here is a simple code:

ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory();
beanFactory.registerSingleton(bean.getClass().getCanonicalName(), bean);

Solution 2 - Java

In Spring 3.0 you can make your bean implement BeanDefinitionRegistryPostProcessor and add new beans via BeanDefinitionRegistry.

In previous versions of Spring you can do the same thing in BeanFactoryPostProcessor (though you need to cast BeanFactory to BeanDefinitionRegistry, which may fail).

Solution 3 - Java

Why do you need it to be of type GenericWebApplicationContext?
I think you can probably work with any ApplicationContext type.

Usually you would use an init method (in addition to your setter method):

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

And you would wire beans by using either

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

or

AutowireCapableBeanFactory.initializeBean(Object existingbean, String beanName)

Solution 4 - Java

Actually AnnotationConfigApplicationContext derived from AbstractApplicationContext, which has empty postProcessBeanFactory method left for override

/**
 * 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) {
}

To leverage this, Create AnnotationConfigApplicationContextProvider class which may look like following(given for Vertx instance example, you can use MyClass instead)...

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);
        }
    };
}
}

While creating ApplicationContext you can create it using

Vertx vertx = ...; // either create or for vertx, it'll be passed to main verticle
ApplicationContext context = new CustomAnnotationApplicationContextProvider(vertx).get(ApplicationSpringConfig.class);

Solution 5 - Java

First initialize Property values

MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();
mutablePropertyValues.add("hostName", details.getHostName());
mutablePropertyValues.add("port", details.getPort());

DefaultListableBeanFactory context = new DefaultListableBeanFactory();
GenericBeanDefinition connectionFactory = new GenericBeanDefinition();
connectionFactory.setBeanClass(Class);
connectionFactory.setPropertyValues(mutablePropertyValues);
            
context.registerBeanDefinition("beanName", connectionFactory);

Add to the list of beans

ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory();
beanFactory.registerSingleton("beanName", context.getBean("beanName"));

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser146714View Question on Stackoverflow
Solution 1 - JavasndyukView Answer on Stackoverflow
Solution 2 - JavaaxtavtView Answer on Stackoverflow
Solution 3 - JavaSean Patrick FloydView Answer on Stackoverflow
Solution 4 - JavayugandharView Answer on Stackoverflow
Solution 5 - JavaTarunView Answer on Stackoverflow