Search code examples
springdependency-injectionapplicationcontext

How to destroy existing bean and replace with new definition Spring - during Runtime


I have a scenario where I have a web app. In my web app I have imported "applicationContext.xml" from 2 another jar files. There are few common beans in the two imported context files. In one of my class in web app I have a situation where I am using functions from both the jars.

Function 1 from jar 1 : getEmployeeDetails() - needs "employeeBean" - "com.practice.Employee"

Function 2 from jar 2 : getEmployeeSalaryBreakup() - needs "employeeBean" - "com.practice.compensation.Employee"

Now the problem is, the second function call is breaking because it is not able to map the bean. It gives classCastException. I am not autowiring beans in my web app, they are being called within jar files.

One of the solutions that I tried was to destroy the existing bean and reinitialize. PSB code for same:

/*
getEmployeeDetails()  //call here, uses employeeBean - com.practice.Employee
*/

ConfigurableApplicationContext configContext = (ConfigurableApplicationContext)applicationContext;

SingletonBeanRegistry registry = configContext.getBeanFactory();

registry.destroyBean("employeeBean"); //trying to destroy existing bean

registry.registerSingleton("employeeBean", "com.practice.compensation.Employee"); //reinitialize bean with new definition

/*
getEmployeeSalaryBreakup() //call here, expecting it will use new bean definition
*/

The above implementation is not working for me, "registry.destroyBean("employeeBean");" - even after execution of this line the old bean definition still persists.

Can somebody suggest what am I missing, or some other solution to accomplish this. As the jar files and their context files are not in my control. So I need to handle this at web app level.


Solution

  • Finally this is how it worked:

    /*
    call function getEmployeeDetails() //uses "employeeBean" - "com.practice.Employee"
    */
    
    BeanDefinitionRegistry beanRegistry = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();
    BeanDefinition newBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(com.practice.compensation.Employee.class).getBeanDefinition();
    BeanDefinition oldBeanDefinition = beanRegistry.getBeanDefinition("employeeBean");//this is needed if u want to revert your bean changes back to how it was
    beanRegistry.registerBeanDefinition("employeeBean", newBeanDefinition);
    
    /*
    call function getEmployeeSalaryBreakup() //this will now execute as it gets required bean "employeeBean" - "com.practice.compensation.Employee"
    */
    
    //reverting back bean changes
    beanRegistry.registerBeanDefinition("employeeBean", oldBeanDefinition);