environment:
spring boot version: 2.7.9 jdk version:1.8
Sample code:
@Service
@Slf4j
public class AopTestService {
public String value = "hello world";
@Retryable
public void proxy(ApplicationContext applicationContext) {
Object obj = applicationContext.getBean(this.getClass());
boolean bool1 = AopUtils.isAopProxy(obj);
boolean bool2 = AopUtils.isAopProxy(this);
log.info("bool1:{},bool2:{},value:{}", bool1, bool2, value);
}
@Retryable
public final void noProxy(ApplicationContext applicationContext) {
Object obj = applicationContext.getBean(this.getClass());
boolean bool1 = AopUtils.isAopProxy(obj);
boolean bool2 = AopUtils.isAopProxy(this);
log.info("bool1:{},bool2:{},value:{}", bool1, bool2, value);
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
proxy
print:
bool1:true,bool2:false,value:hello world
noProxy
print:
bool1:true,bool2:true,value:null
When the noProxy
method is not successfully proxyed because it is final
, but the class AopTestService
is successfully proxyed, the proxy class fails to access the class variable because it can only proxy the method, not the property.
I can't access my own member variables in my own class,it's kind of weird, isn't it?
Comment From: mdeinum
It isn't weird, that is the nature of class based proxies. What happens with the final
method is that it is, indeed, directly invoked on the proxy and not passed on the the proxied object (the wrapped) object. As the proxy is only a dummy instance/empty instance of a class it has none of its properties set.
The non-final
method will be proxied and the method call will eventually pass on to the wrapped object and invoked on that, the actual object that has the values.
This is the nature/caveat of using class based proxies. This is also (somewhat) mentioned in the documentation.
Comment From: nyingping
@mdeinum Thanks for your reply.
Yes, I understand that.
spring's dynamic proxy instantiates objects through Objenesis+cglib, as I know from the source code. Objenesis skips constructors, so the dynamic proxy class can't get the property values of the parent class.
Is the above statement true? If so, what's the point? Forgive me for not finding the relevant documentation. I would appreciate it if you could answer my questions.
Comment From: mdeinum
Yes, because the proxies task is to intercept the method call, do something before/after and then call the method on the parent. However with a final
method there is no way that the method can be overridden to add behavior (the same applies to private
or package default methods), with the result that it will not pass on to the parent but directly invoked on the proxy.
This is simply a limitation of class based proxies, and has been for as long those existed. The same issues are in the EJB world where they use the same approach (it isn't solely bound to Spring but rather all technologies that use these kind of class based proxies).
It is a well documented (but not always understood) limitation.
Comment From: nyingping
Thank you for your explanation.
My understanding is that the dynamic proxy class in spring cannot access the properties of the parent class because it uses Objenesis to bypass the constructor to instantiate the object, whereas as far as I know, cglib implements dynamic proxies directly that can access the properties of the parent class.
Thanks again for your reply.
Comment From: simonbasle
thank you for chiming in @mdeinum, closing this as invalid+for:stackoverflow as this is an (answered) question