For doing this, we need the Spring Application context. For this to accomplish, one can declare one dedicated Spring context bean, which will implement the ApplicationContextAware and BeanFactoryPostProcessor interfaces. This should look something like this:
public class MyContextWrapper implements ApplicationContextAware,
BeanFactoryPostProcessor {
private ApplicationContext appContext;
private ConfigurableListableBeanFactory factory;
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory)
throws BeansException {
this.factory = factory;
}
public void setApplicationContext(ApplicationContext c)
throws BeansException {
this.appContext = c;
}
//setters and getters
}
The postProcessBeanFactory will be executed after reading the configuration files of the spring context. Here one can do other configurations and bean loading, or save the factory for later use.
The Spring application context can be used for later dynamic bean retrieval or other purposes.
For this approach to work, one should let spring load this bean in to it's context by declaring the bean in the XML configuration file as follow:
Now this bean can be loaded in any other bean of the application via referencing it:
Now that we have the grip of the Spring context and it's factory, we can create beans dynamically. For this purpose, we can use the GenericBeanDefinition which allows to load bean definitions as follows:
BeanDefinitionRegistry registry = ((BeanDefinitionRegistry )factory);
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(MyBeanClass.class);
beanDefinition.setLazyInit(false);
beanDefinition.setAbstract(false);
beanDefinition.setAutowireCandidate(true);
beanDefinition.setScope("session");
registry.registerBeanDefinition("dynamicBean",beanDefinition);
As one can see, this bean is created in the session scope and will be stored in the session of the user. The property auto wire candidate tells spring if dependency's of the bean such as setter's or getter's or constructor argument's should be handled automatically by Spring. The property lay init tells Spring if this bean should be instantiated when needed.
To get a handle of Spring bean, one can use the Spring application context as follows:
Object bean=
getApplicationContext().getBean("dynamicBean");
if(bean instanceof MyBeanClass){
MyBeanClass myBean = (MyBeanClass) bean;
// do with the bean what ever you have to do.
}
As you can see, the dynamic bean creation in Spring is no big deal.It is easy to use, an certainly handy in many situations.
this is a cool walkthrough. cheers.
ReplyDeleteI get a type cast error when i do this :
ReplyDeleteHere my factory bean is a SchedulerFactoryBean.
Can you help ?
Thanks,
Kris
Sorry Kris, I can't see your code. Is this type cast error when you cast on ShedulerFactoryBean or is it thrown when this factroy is giving you a handle on a bean. If the later is the case, I would recommend to see if the name you use is the correct name of your bean and if you cast it to the right type.
ReplyDeleteHope it works for you.
@luca ghirotti
thanx
hi agema, thanks for the information. I am new to spring.
ReplyDeleteI am extending an existing application which uses spring and properties like datasource, user credentials are added in the context before initialise. however this will not suit for my enhancement, I am looking to change some properties like datasource name, user credentials during runtime. Could you please share your thoughts, whether can I use Beandefinition and set the properties,
I have added something like this, by my problem is, when i register the bean definition, will the parent applicationcontext holds this new bean value?
BeanDefinition definition = new RootBeanDefinition(PseudoDataSource.class);
ApplicationContext context = new ClassPathXmlApplicationContext("WEB-INF/applicationContext.xml");
definition.getPropertyValues().addPropertyValue("driverName", "");
definition.getPropertyValues().addPropertyValue("dataSourceName", "");
definition.getPropertyValues().addPropertyValue("userName", "");
definition.getPropertyValues().addPropertyValue("password", "");
Object bean = context.getBean("myBeanFactory");
BeanDefinitionRegistry registry = ((BeanDefinitionRegistry )(DataSourceBeanPostProcessor)bean);
registry.registerBeanDefinition("schemaDataSource", definition);
can you please help?
Hi valluri, I haven't done such thing before. But why trying to change the configuration. Let Spring create you a new Instance of the Bean and change the properties on the fresh instance. I don't know if that will work, but it is a worth of trying.
ReplyDeleteHope it helps somehow.
kind regards.
Thank you very much for the information it is very helpful.
ReplyDeleteregards
rajesh