David_W (70) [Avatar] Offline
#1
I assume that using aop:aspectj-autoproxy proxy-target-class="true" would also remove the problem of advising method via call this.isProductAvailable, described in 9.2.5
ramnivas (171) [Avatar] Offline
#2
Re: Note about proxy-target-class in 9.3
The proxy-target-class attribute governs if the proxy implements the interfaces or extends the target class. However, the delegation scheme described in figure 9.2 still remains in place (proxy delegate to the target object). Hence the self-call problem also remains the same.

-Ramnivas
David_W (70) [Avatar] Offline
#3
Re: Note about proxy-target-class in 9.3
But using cglib with proxy-target-class means that the proxy extends the target class. Within the target class, then, 'this' is actually the proxy subclass, isn't it? So a self-call should still go through the proxy subclass and advice would apply. Or is it implemented as the proxy subclass containing an instance variable which points to the target, and the target is not the cglib subclass? If so, is it done this way for consistency, or some other reason?
David_W (70) [Avatar] Offline
#4
Re: Note about proxy-target-class in 9.3
If the proxy contains an instance var that references the target and delegates to it, instead of just extending the target class, how does it deal with final methods? For example,

public class CGLibProxy extends SomeTargetClass {
public void someAdvisedMethod() {
do advice stuff;
super.someAdvisedMethod();
}
}

so a self call to someAdvisedMethod would work as well as an external call to the method and the only methods that have to be overridden in CGLibProxy are those methods that are advised. If, instead, the proxy class handles all method calls and delegate to the target class, we have


public class CGLibProxy extends SomeTargetClass {
private SomeTargetClass target = ...;
public void someAdvisedMethod() {
do advice stuff;
target.someAdvisedMethod();
}
}

In this format, the CGLibProxy would have to override all of the methods from SomeTargetClass. This obviously causes problems with final methods - the first approach would work fine as long as you don't try to advise a final method, but the second approach fails if any final method exists, even if you don't try to advise it.
ramnivas (171) [Avatar] Offline
#5
Re: Note about proxy-target-class in 9.3
Spring uses the delegation approach (equivalent to you second code snippet). This way two objects exist (target and proxy). It allows target to be wrapped in multiple proxies if needed.

As for final methods, using class-based proxy poses a problem as you noted and as section 9.2.3 notes as well. Essentially, there will be no advice applied to a final method.

-Ramnivas
David_W (70) [Avatar] Offline
#6
Re: Note about proxy-target-class in 9.3
But the delegation approach from the second example would have a problem if there was ANY final method on the target class, even if there was no advice to be applied for it. Interesting implementation choice smilie
ramnivas (171) [Avatar] Offline
#7
Re: Note about proxy-target-class in 9.3
It will be a problem only for the final methods. The CGLIB generated subclass won't (and can't) have overriden final methods, but it can override non-final methods (subject to, of course, access specification). So the delegation and advising will work just fine for non-final methods.
David_W (70) [Avatar] Offline
#8
Re: Note about proxy-target-class in 9.3
OK. I have a class
public class Foo {
public void stuff() {
...
}
public void other() {
...
}
}

and I have an aspect advising method stuff only - not method other, with proxy-target-class=true. Then, if it uses the delegation style, we would end up with something like

public class CGLibFoo {
private Foo target;
public void stuff() {
do advice;
target.stuff();
}

public void other() {
target.other();
}
}

So, the proxy needs to override all methods from Foo in order to delegate to them. The above works fine, but what happens if my original Foo had
public final void other()?
Now, CGLibFoo can't work, since it can't override other, even though we have no advice to apply for the method.

To summarize, it sounds as if the delegation approach using proxy-target-class fails if ANY method on the target class is final, not just methods that are being advised.
ramnivas (171) [Avatar] Offline
#9
Re: Note about proxy-target-class in 9.3
Good point.

Since proxy cannot override a final method, any invocation of such a method will get directed to the proxy itself (Spring produces a warning such as "WARN : org.springframework.aop.framework.Cglib2AopProxy - Unable to proxy method [public final <your-final-method>] because it is final: All calls to this method via a proxy will be routed directly to the proxy."

What happens when such call gets directed directly to the proxy? It depends on what the final method is doing. If it accesses an injected dependency, it will lead to a NullPointerException (target's dependencies will be set, but not the proxy's), unless there is a default value for the dependency. In case of default value for dependency, it will lead to potentially subtle issues (incorrect state). In general, this warning is a bad news (unless you can be certain that no one invokes the final method).

I will update Spring's warning message to be more prominent and descriptive. I will also update the book to clarify this situation.

-Ramnivas