Skip to content

Instantly share code, notes, and snippets.

@zhanggang807
Created January 12, 2018 05:55
Show Gist options
  • Save zhanggang807/a6b1606e6d2f4eba8c039b209692ef05 to your computer and use it in GitHub Desktop.
Save zhanggang807/a6b1606e6d2f4eba8c039b209692ef05 to your computer and use it in GitHub Desktop.
dynamic proxy of CG lib
public class UserServiceImpl {
public void add() {
System.out.println("This is add service");
}
public void delete(int id) {
System.out.println("This is delete service?delete " + id);
}
}
class MyMethodInterceptor implements MethodInterceptor {
public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) throws Throwable {
System.out.println("Before:" + method);
Object object = proxy.invokeSuper(obj, arg);
System.out.println("After:" + method);
return object;
}
}
class TestCGLibProxy {
/**
* 代理对象的生成过程由Enhancer类实现,大概步骤如下:
1、生成代理类Class的二进制字节码;
2、通过 Class.forName加载二进制字节码,生成Class对象;
3、通过反射机制获取实例构造,并初始化代理类对象。
4、通过System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "file path"); //生成class文件
* @param args
*/
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, System.getProperty("user.home") + File.separator + "Desktop"); // 生成class文件
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserServiceImpl.class);
enhancer.setCallback(new MyMethodInterceptor());
UserServiceImpl userService = (UserServiceImpl) enhancer.create();
System.out.println("=====================");
userService.add();
System.out.println("=====================");
userService.delete(8);
System.out.println("=====================");
}
/**
5、使用 反编译工具 procyon 查看代理类实现
通过CGLIB生成的字节码相比JDK实现来说显得更加复杂。
1、代理类 UserService$$EnhancerByCGLIB$$394dddeb继承了委托类 UserSevice,且委托类的final方法不能被代理;
2、代理类为每个委托方法都生成两个方法,以add方法为例,一个是重写的add方法,一个是CGLIB$add$0方法,该方法直接调用委托类的add方法;
3、当执行代理对象的add方法时,会先判断是否存在实现了MethodInterceptor接口的对象 cglib$CALLBACK_0,如果存在,则调用MethodInterceptor对象的 intercept方法:
参数分别为:1、代理对象;2、委托类方法;3、方法参数;4、代理方法的MethodProxy对象。
4、每个被代理的方法都对应一个MethodProxy对象, methodProxy.invokeSuper方法最终调用委托类的add方法,实现如下:
*/
//参考资料 出处 http://mp.weixin.qq.com/s/iedEtNDp-u9C1RGvqj3Juw --> https://www.jianshu.com/p/13aa63e1ac95
}
/**
* FastClass实现机制 //todo 这个要好好了解下具体原理
*
* FastClass其实就是对Class对象进行特殊处理,提出下标概念index,通过索引保存方法的引用信息,
* 将原先的反射调用,转化为方法的直接调用,从而体现所谓的fast,下面通过一个例子了解一下FastClass的实现机制
*
* 在FastTest中有两个方法,getIndex中对Test类的每个方法根据hash建立索引,invoke根据指定的索引,直接调用
* 目标方法,避免了反射调用。所以当调用methodProxy.invokeSuper方法时,实际上是调用代理类的CGLIB$add$0方法,
* CGLIB$add$0直接调用了委托类的add方法。
*
*
*/
class Test {
public void f() {
System.out.println("f method");
}
public void g() {
System.out.println("g method");
}
}
class FastTest {
public int getIndex(String signature) {
switch (signature.hashCode()) {
case 3078479:
return 1;
case 3108270:
return 2;
}
return -1;
}
public Object invoke(int index, Object o, Object[] ol) {
Test t = (Test) o;
switch (index) {
case 1:
t.f();
return null;
case 2:
t.g();
return null;
}
return null;
}
}
/**
* 总结 jdk和cglib动态代理实现的区别
1、jdk动态代理生成的代理类和委托类实现了相同的接口;
2、cglib动态代理中生成的字节码更加复杂,生成的代理类是委托类的子类,且不能处理被final关键字修饰的方法;
3、jdk采用反射机制调用委托类的方法,cglib采用类似索引的方式直接调用委托类方法;
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment