Reputation: 109
So I have been trying to wrap my head around cglib proxy . So from what i understand it should roughly inherit the target class we are proxying and essentially inject another instance of the target which is actually invoked inside it.
So , for example I have this as the class -
@Component
public class A {
private String silly ="a";
public final void processMyStuff() {
System.out.println(this.silly + "b");
}
}
The aspect is declared by a class like -
@Component
@Aspect
public class ProfileAspect {
private static Logger log = LoggerFactory.getLogger("ProfileLogger");
@Around("publicMethods()")
public Object profileLogging(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Long startTime = System.currentTimeMillis();
Object proceed = proceedingJoinPoint.proceed();
Long endTime = System.currentTimeMillis();
log.info("responseTime: {} ms for class {} in method {}",
(endTime - startTime),
proceedingJoinPoint.getTarget().getClass().getName(),
proceedingJoinPoint.getSignature().getName());
return proceed;
}
@Pointcut("execution(public * Service.A.*(..))")
private void publicMethods() { }
}
So , as expected when I do the following -
//where "a" is a spring managed instance which we have simply injeted at the point of invocation
a.processMyStuff();
The output is -
nullb
So my main query here is this -
If I do write similar code in plain java , the parent classes instance variable is referred when a final method is invoked in a similar fashion via the instance of the child class. So the output there would be "ab".
With cglib from what i understood final methods should be unaffected, so in this case why is the proxy's value of the instance variable "silly" (null) is printed ?
Edit 2:
So just to share the normal java code that should in theory map to what a proxy does -
public class A {
private String silly ="a";
public final void processMyStuff() {
System.out.println(this.silly + "b");
}
}
inherited class [ equivalent of the proxy class] -
public class B extends A {
private A a;
public B (A a){
this.a = a;
}
}
invocation -
B b = new B(new A());
b.processMyStuff();
outupt - ab
So, the comparative output is "ab" . So I am trying to understand what I am understanding wrong here.
Edit 3: So as per my current understanding of cglib could in theory delegate calls to the superclass but it seems like it delegates them to another instance.
This is a me trying to create a proxy object using springs constructs directly -
class AdviceInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
// run code before method execution
System.out.print("Before target method execution " + invocation.getMethod().getName());
// target method execution
Object retVal = invocation.proceed();
System.out.println("After target method execution " + invocation.getMethod().getName());
return retVal;
}
}
Target class -
public class Mutant {
public String name="aa";
/**
* Enhancer requires the no-arg constructor to construct the proxy instance.
* IllegalArgumentException is thrown if Enhancer can't find the no-arg
* constructor during proxy creation time.
*/
public Mutant() {
System.out.println("in consutructor" + this.name+ this.getClass());
}
public String getName() {
System.out.println("Mutant get name.."+ this.getClass().toString());
return name;
}
public final void eat() {
System.out.println("Mutant eat.."+name+ this.getClass());
}
public void eatPotato() {
System.out.println("Mutant eatpotato.."+name+ this.getClass());
}
}
Mutant target = new Mutant();
ProxyFactory pf = new ProxyFactory();
// Add MethodInterceptor as advice
pf.addAdvice(new AdviceInterceptor());
// set the target class you want to proxy
pf.setTarget(target);
// Get the proxy
Mutant proxy = (Mutant) pf.getProxy();
// Call target class print function via proxy
proxy.eatPotato();
proxy.eat();
Output -
Before target method execution eatPotatoMutant eatpotato..aaclass com.ie.naukri.feature.companyservice.Mutant
After target method execution eatPotato
Mutant eat..nullclass com.ie.naukri.feature.companyservice.Mutant$$EnhancerBySpringCGLIB$$46a1e333
So the invocation of the final method shows the instance variable as null. Stepping through the code, I found during the instantiation of the proxy object, spring seems to call -
SpringObjenesis#newInstance
This is used to create the proxy instance, simply using this to create a new instance of a random class also seems to set the instance variables to null!
Edit 4: So I just tried stepping through the code of my actual service which was using aspects with cglib . I put the debuggers in the classes I mentioned above and voila, spring went there to create its proxy instances!
Edit 5: Narrower question - cglib proxy and null instance variable internals
Upvotes: 0
Views: 74