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