How do I programmatically add a @Bean definition to a Spring context?
I usually add my objects to spring context using the definition @Bean
:
@Autowired
private SpringBus bus;
//register a singleton
@Bean
public WebservicePort getPort() {
//new port()
//initialize
//configure
//return port;
}
But now I need deeper control of the process, especially I want to dynamically create the bean name under which the bean is registered.
I tried:
@Service
public class MyPortRegistrar implements BeanDefinitionRegistryPostProcessor {
@Autowired
private SpringBus bus;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println(bus); //prints null
//create and configure port with the SpringBus
Port port = new WebservicePort(bus); // -> throws NullPointerException
beanFactory.autowireBean(port);
beanFactory.initializeBean(port, "myDynamicPortName");
}
}
But this throws out the NPE since already authorized dependencies are not initialized here.
So how can I add these beans programmatically?
source to share
You have to autwire bean factory and use @PostConstruct
bean to register. This way you ensure that all dependencies have been injected (the bean factory is injected by the container, no setup required).
@Service
public class MyPortRegistrar {
@Autowired
private ConfigurableBeanFactory beanFactory;
@Autowired
private SpringBus bus;
@PostConstruct
public void createPort() {
Port port = new WebservicePort(bus);
beanFactory.registerSingleton("myDynamicPortName", port);
}
}
source to share
You have to put this before:
beanFactory.autowireBean(port);
But if you want to initialize the bean, I think you want to create one instance (I say this because you used annotation in the example @Bean
):
beanFactory.initializeBean(port, "myDynamicPortName");
instead of singleton:
beanFactory.registerSingleton("myDynamicPortName", port);
source to share
An alternative to Khalid's answer (which I think requires some additional dependencies and configuration) is to implement the InitializingBean interface:
@Service
public class MyPortRegistrar implements InitializingBean {
@Autowired
private SpringBus bus;
@Autowired
private ConfigurableBeanFactory beanFactory;
@Override
public void afterPropertiesSet() throws Exception
System.out.println(bus); //prints null
//create and configure port with the SpringBus
Port port = new WebservicePort(bus); // -> throws NullPointerException
beanFactory.autowireBean(port);
beanFactory.initializeBean(port, "myDynamicPortName");
}
}
source to share