I need a service (singleton fits) with some internal fields, like a list of pending threads (yes everything is written to be thread safe) the problem is that if I @autowire this bean, fields appear to be empty. Debugging I see that the proxy correctly binds to the instance (fields CGLIB$CALLBACK_X are correctly linked to the populated bean) with populated fields, but the fields it offers are empty.
The following lines of codes give a general idea of what i’m talking about.
@Service
public class myService{
@Autowired
private Monitor monitor;
public List getSomething(){
return monitor.getList();
}
}
@Service
public class myStatefulService{
//This field will be populated for sure by someone before getSomething() is called
private List list;
public synchronized List getSomething(){
return this.list;
}
//Called by other services that self inject this bean
public synchronized void addToList(Object o){
this.list.add(o);
}
}
Debugging the variable monitor during the getList call I get
monitor => instance of correct class
fields:
CGLIB$BOUND => true
CGLIB$CALLBACK_0.advised => proxyFactory (correct)
CGLIB$CALLBACK_1.target (reference to the correct instance of myStatefulService class)
fields:
list => [.........] (correctly populated)
CGLIB$CALLBACK_2 .....
......
......
......
list => [] (the list that would be populated is empty instead)
Are you curious or you have some real issue? Nevertheless here is an explanation.
When using CGLIB to proxy classes Spring will create a subclass called something like
myService$EnhancerByCGLIB. This enhanced class will override some if not all of your business methods to apply cross-cutting concerns around your actual code.Here comes the real surprise. This extra subclass does not call
supermethods of the base class. Instead it creates second instance ofmyServiceand delegates to it. This means you have two objects now: your real object and CGLIB enhanced object pointing to (wrapping) it.The enhanced class is just a dummy proxy. It still has the same fields as your base class (inherited from it) but they are not used. When you call
addToList()onmyService$EnhancerByCGLIBobject it will first apply some AOP logic, calladdToList()ofmyService(which it wraps) and apply remaining AOP logic on return. ThemyService$EnhancerByCGLIB.listfield is never touched.Why can’t Spring use the same class and delegate via
super? I guess for simplicity: first create “raw” bean and then apply AOP proxying during post-processing.