Reputation: 1472
I have a scenario where I need to initialize a bean based on application configuration during startup. Later, due to dynamic configuration fetched based on an event, I have to update the bean.
This bean can't be updated but can only be replaced with a new instance.
Does using the new
operator initialize only the local instance or will it change the bean?
@Component
public class TestComp {
@Autowired
private BeanA beanA;
public void updateBean() {
beanA = new BeanA("new value");
}
}
I referred the bean in another class and checked after I initialized it with new
. It reflected the new object. But, I need a confirmation from experts if it does.
Upvotes: 2
Views: 5227
Reputation: 49656
I have a scenario where I need to initialize a bean based on application configuration during startup.
It's fine. The singleton scope is a good choice here.
Later, due to dynamic configuration fetched based on an event, I have to update the bean.
It's a problem. Updating a bean in the context is a complex process: you need to remove the existing bean definition, add a new one, and update all the beans that are somehow related to the bean (reinitialise these components, refresh the context). Technically, it's possible and it has been simplified by Spring Cloud's @RefreshScope
.
Does using new operator initialize only the local instance or will it change the bean?
It affects only the field in this class. No one is aware of the change. ApplicationContext#getBean
still will return the old object, and all the components will be (or have already been) initialised with the old instance.
I referred the bean in another class and checked after I initialized it with new. It reflected the new object.
It can't be true. Probably, it refers to the TestComp#beanA
field, not to its own BeanA
field.
The solution I am suggesting is to define a custom bean scope based on the events you are receiving. It will keep the bean and the context updated.
Upvotes: 2
Reputation: 106490
It sounds like you want a factory instead. Below is a rough idea of what that might look like; your needs may vary.
@Component
public class BeanFactory {
private volatile BeanA beanAInstance;
public BeanA createBeanA(String value) {
if (null == beanAInstance) {
synchronized (this) {
if (null == beanAInstance) {
beanAInstance = new BeanA(value);
}
}
}
return beanAInstance;
}
public void refreshBeanA(String newValue) {
synchronized (this) {
beanAInstance = new BeanA(newValue);
}
}
}
You then wire this in, and based on configuration, you can then refresh and use the new value. Bear in mind that this would change the value you get from this bean.
Upvotes: 1