Home » Spring register bean at runtime

Spring register bean at runtime

Spring register bean at runtime

1. Overview

In this article, we will learn to register the Spring bean at runtime. Sometimes, you want to register the beans programmatically based on some condition or dynamically.

If you are not familiar with Spring bean instantiation, see this article.

2. Spring register bean -BeanDefinitionRegistryPostProcessor

One way to do this is by using the BeanDefinitionRegistryPostProcessor.

The ApplicationContext auto-detects BeanFactoryPostProcessor beans in its bean definitions and apply them before any other beans get created. This BeanFactoryPostProcessor is an extension point to customize the bean definitions or configuration metadata of the bean before the creation of the beans. 

The BeanDefinitionRegistryPostProcessor allows the registration of further bean definitions before regular BeanFactoryPostProcessor detection kicks in.

2.1. Implement BeanDefinitionRegistryPostProcessor

To add a new bean definition, you can create an implementation of the BeanDefinitionRegistryPostProcessor and override the method postProcessBeanDefinitionRegistry.

In this postProcessBeanDefinitionRegistry method, you can change the application context’s internal bean definition registry after its standard initialization. Though all regular bean definitions are loaded, no beans have been instantiated yet.

This allows space for adding further bean definitions.

Note that we annotated this class with @Component to allow the Spring application to scan this class.

@Component
public static class BeanRegistration implements BeanDefinitionRegistryPostProcessor {
	@Override
	public void postProcessBeanDefinitionRegistry(
		BeanDefinitionRegistry bdr) throws BeansException {
	}
	@Override
	public void postProcessBeanFactory(
		ConfigurableListableBeanFactory clbf) throws BeansException {
	}
}

2.2. Register bean programmatically

The postProcessBeanDefinitionRegistry method is invoked with the bean definition registry used by the application context.

You must call registerBeanDefinition on the bean definition registry to register a new bean definition. This registerBeanDefinition takes the bean name and definition as input.

You can use the BeanDefinitionBuilder to create a BeanDefinition programmatically (introduced in Spring 2.0).

bdr.registerBeanDefinition("customBean",
		BeanDefinitionBuilder.genericBeanDefinition(CustomBean.class,
		() -> new CustomBean("Custom Bean Constructor Argument")).getBeanDefinition());

In the below code, we are using the genericBeanDefinition builder method to create a new Bean definition.

public static <T> BeanDefinitionBuilder genericBeanDefinition(Class<T> beanClass, Supplier<T> instanceSupplier) 
// bean class
// a callback for creating an instance of the bean
@Override
public void postProcessBeanDefinitionRegistry(
	BeanDefinitionRegistry bdr) throws BeansException {
	bdr.registerBeanDefinition("customBean",
			BeanDefinitionBuilder.genericBeanDefinition(CustomBean.class,
			() -> new CustomBean("Custom Bean Constructor Argument")).getBeanDefinition());
}

3. Spring register bean using ApplicationContextInitializer

You can implement the ApplicationContextInitializer to register the bean programmatically. It is essentially code that gets executed before the Spring application context gets completely created.

In this class, you can call registerBean and register the bean programmatically.

public class ProgrammaticApplicationContextInitializer implements
		ApplicationContextInitializer<GenericApplicationContext> {
	@Override
	public void initialize(GenericApplicationContext applicationContext) {
		applicationContext.registerBean(CustomBean.class, "Custom  Bean initialization");
	}
}

If you are not using the Spring boot, then you can register the application context as below:

public static void main(String[] args) {
	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanfactoryApplication.class);
	ProgrammaticApplicationContextInitializer programmaticApplicationContextInitializer =
			new ProgrammaticApplicationContextInitializer();
	programmaticApplicationContextInitializer.initialize(applicationContext);
}

If you are using Spring Boot, you can register it straightforwardly:

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class BeanfactoryApplication {
 public static void main(String[] args) {
  new SpringApplicationBuilder(BeanfactoryApplication.class)
    .initializers(new ProgrammaticApplicationContextInitializer())
    .run(args);
// or
// You can also add them on your SpringApplication before running it
   application.addInitializers(ProgrammaticApplicationContextInitializer.class);
   application.run(args);
 }
}

You can register them in META-INF/spring.factories

org.springframework.context.ApplicationContextInitializer=\
com.tedblob.ProgrammaticApplicationContextInitializer

You can add it to the web.xml for a Spring web application:

<context-param>
    <param-name>contextInitializerClasses</param-name>
    <param-value>com.tedblob.ProgrammaticApplicationContextInitializer</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

You can also add it to the application properties file or external properties:

context.initializer.classes=com.tedblob.ProgrammaticApplicationContextInitializer

4. Register bean at runtime using BeanFactory

Alternatively, you can use the BeanFactory or ApplicationContext to register a bean by invoking the registerBean method. However, bean definitions do not exist for this type of registration.

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanfactoryApplication.class);
reader.loadBeanDefinitions(new ClassPathResource("config.xml"));
applicationContext.registerBean(CustomBean.class, "custom bean");
CustomBean customBean = applicationContext.getBean(CustomBean.class);
System.out.println(customBean.getValue() + "");

5. Register runtime using BeanDefinitionRegistry

The BeanDefinitionRegistry is the only interface in Spring’s bean factory packages that encapsulates the registration of bean definitions. You can use this registry to remove or register the beans dynamically.

To register a new bean definition, use registerBeanDefinition.

registry.registerBeanDefinition(beanId, newBeanObj);

To remove an existing bean definition, use removeBeanDefinition.

registry.removeBeanDefinition(beanId);

You can remove and add a new bean definition at runtime by using the following code:

 AutowireCapableBeanFactory factory = 
                   applicationContext.getAutowireCapableBeanFactory();
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) factory;
registry.removeBeanDefinition(beanId);
registry.registerBeanDefinition(beanId, newBeanObj);

6. Conclusion

To sum up, we have learned to register a bean at runtime in a Spring application. You can find code samples of this article in our GitHub repository.