silver-soul
silver-soul

Reputation: 109

cglib proxy and null instance variables

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

Answers (0)

Related Questions