Use cglib to extend class
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);