Use cglib to extend class

java

cglib is a code generator library. It can generate and transform Java byte code. The generated class is a subclass of original class. See code below.

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;

public class ProxyTest {
  interface Run {
    void run();

    void done();
  }

  static class RunImpl implements Run {
    @Override
    public void run() {
      System.out.println("running");
    }

    @Override
    public void done() {
      System.out.println("done");
    }
  }

  public static void main(String[] args) {
    // save generated class to current dir
    System.setProperty("cglib.debugLocation", ".");
    Enhancer enhancer = new Enhancer();
    // cglib can extend class
    enhancer.setSuperclass(RunImpl.class);
    // define what to do when invoke original method
    MethodInterceptor methodInterceptor = (obj, method, args1, proxy) -> {
      System.out.println("before " + method.getName());
      try {
        return proxy.invokeSuper(obj, args1);
      } finally {
        System.out.println("after " + method.getName());
      }
    };
    enhancer.setCallback(methodInterceptor);
    Run runProxy = (Run) enhancer.create();
    runProxy.run();
    runProxy.done();
  }
}

During execution, 3 class are generated. One is a subclass of RunImpl. Another 2 are FastClass. FastClass is a class which can call class’s method by index or signature very fast. If no such index, we need to find the method first and then call method.invoke(obj, args) by reflection which is slow then call method directly.

FastClass is something like a symbol table of class methods as below. Method can 
be found quickly by its signature.

switch(method) {
 case "toString": obj.toString();
 case "equals": obj.equals(args[0]);
 case "run": obj.run();
 case "done": obj.done();
}
Above is a simplified version for demonstrating purpose. 
Actually, method will be converted to int index based on its signature first
and then it can be called using the index.

If no FastClass, it's kind of like:

Method method = class.getDeclaredMethod(name, argTypes);
method.invoke(obj, args);