when will a prototype bean get garbage collected if we use proxy mode for scope prototype for a class in Spring boot, is it handled by Spring?
when the object of MyClassB will get garbage collected in below example or is it leading to a memory leak?
@Service
public class MyClassA {
@Autowired
private MyClassB myClassB;
public String findMydata(String input) {
String myData = myClassB.getSomeData(input);
return myData;
}
}
Below is the class with scope prototype which is used by above class
@Service
@Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE,
proxyMode=ScopedProxyMode.TARGET_CLASS)
public class MyClassB {
MyPojoClassA mypojoA = null;
MyPojoClassB mypojoB = null;
@Autowired
private MyClassC myClassC;
@Autowired
private myClassD myClassD;
public String getSomeData(String input) {
String SomeData = "";
myMethodA(input);
// makes call to external service for data
SomeData = myClassC.getSomeData(mypojoA.getSomething());
myMethodB(mypojoA.getSomeOthervalue());
if(SomeData.isBlank()){
// retrieve the data from database.
SomeData = myClassD.getSomeData(mypojoB.getSomething());
}
return SomeData;
}
private void myMethodA(String input){
// process and set values in mypojoA
}
private void myMethodB(String input){
// process and set values in mypojoB
}
}
The usage and assigning values to different fields of myPojoA and myPojoB is done multiple times by calling different private methods inside method getSomeData. here in code sample I have not made those calls for simplicity, but have to show that there are two instance level reference variables of two classes being used.
If an object is not referenced / used by other objects, it is eligible for GC. (Source , see the section Describing Garbage Collection).
In your example , though you are injecting a prototyped MyClassB
into an singleton MyClassA
, MyClassA will always access to the same MyClassB
instance mainly because injection of MyClassB
into MyClassA
will only happen once when instantiating MyClassA
. This behaviour is well explained in the docs as follows:
When you use singleton-scoped beans with dependencies on prototype beans, be aware that dependencies are resolved at instantiation time. Thus, if you dependency-inject a prototype-scoped bean into a singleton-scoped bean, a new prototype bean is instantiated and then dependency-injected into the singleton bean. The prototype instance is the sole instance that is ever supplied to the singleton-scoped bean.
However, suppose you want the singleton-scoped bean to acquire a new instance of the prototype-scoped bean repeatedly at runtime. You cannot dependency-inject a prototype-scoped bean into your singleton bean, because that injection occurs only once, when the Spring container instantiates the singleton bean and resolves and injects its dependencies.
As MyClassA
is a singleton , it always exist during the application runs. It means its dependencies (i.e MyClassB
) will always be used by that MyClassA
instance and they will never be eligible for GC.
If you want to create a new MyClassB
instance whenever MyClassA
accesses MyClassB
, you can use one of the following technique describe here. Just make sure the new MyClassB
instance will never be assigned to the fields of some singleton bean , then it will be eligible to be GC when that method exit. Something like:
@Service
public class MyClassA {
@Autowired
private Provider<MyClassB> myClassB;
public String findMydata(String input) {
MyClassB classB = myClassB.get();
String myData = classB.getSomeData(input);
return myData;
}
}
I am using technique 5 described at this.