前言:

这2种动态代理算是老生常谈的吧,面试还是会经常问到的,下面做下分析:

jdk动态代理:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class JdkHanler implements InvocationHandler { private Object target; public Object invoke(Object proxy, Method method, Object[] arg) throws Throwable {
System.out.println("before");
Object o=method.invoke(target, arg);
System.out.println("after");
return o;
}
public JdkHanler(Object target) {
super();
this.target = target;
}
public Object getInstance(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
}

cglib动态代理:

import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; public class HelloWorldInterceptor implements MethodInterceptor { private Object target; public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before");
Object r=proxy.invokeSuper(obj, args);
System.out.println("after");
return r;
}
public HelloWorldInterceptor(Object target) {
super();
this.target = target;
}
public Object getInstance(){
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
}

测试类:

public class AllTest {

    public static final String output="D:/SpringWorkSpace/";
//cglib生成代理类字节码文件
static{
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, output);
} @Test
public void proxyTest(){
HelloWorldInterceptor interceptor=new HelloWorldInterceptor(new HelloWorldImpl());
HelloWorld h=(HelloWorld) interceptor.getInstance();
h.sayHello();
}
//@Test
public void jdkproxyTest() throws IOException{
JdkHanler hanler=new JdkHanler(new HelloWorldImpl());
HelloWorld h=(HelloWorld) hanler.getInstance();
h.sayHello();
jdkToFile(h);
}
//jdk代理类字节码文件
public static void jdkToFile(HelloWorld obj) throws IOException {
Class clazz = obj.getClass();
String className = clazz.getName();
byte[] classFile = ProxyGenerator.generateProxyClass(className, HelloWorldImpl.class.getInterfaces());
FileOutputStream fos = new FileOutputStream(output+"proxy.class");
fos.write(classFile);
}
}

利用jd-gui工具反编译字节码文件:

生成的jdk代理类:

public final class $Proxy4 extends Proxy
implements HelloWorld
{
private static Method m3;
private static Method m1;
private static Method m0;
private static Method m2; public $Proxy4(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
//调用sayHello方法
public final String sayHello()
throws
{
try
{
//调用JdkHanler的invoke方法
return (String)this.h.invoke(this, m3, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
} static
{
try
{
m3 = Class.forName("com.selrain.DynamicProxy.HelloWorld").getMethod("sayHello", new Class[0]);
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}

生成的cglib代理类:

public class HelloWorld$$EnhancerByCGLIB$$d87b5f2a extends HelloWorld
implements Factory
{
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private static Object CGLIB$CALLBACK_FILTER;
private static final Method CGLIB$sayHello$0$Method;
private static final MethodProxy CGLIB$sayHello$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$hashCode$1$Method;
private static final MethodProxy CGLIB$hashCode$1$Proxy;
private static final Method CGLIB$clone$2$Method;
private static final MethodProxy CGLIB$clone$2$Proxy;
private static final Method CGLIB$equals$3$Method;
private static final MethodProxy CGLIB$equals$3$Proxy;
private static final Method CGLIB$toString$4$Method;
private static final MethodProxy CGLIB$toString$4$Proxy; static void CGLIB$STATICHOOK1()
{
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class localClass1 = Class.forName("com.selrain.DynamicProxy.HelloWorld$$EnhancerByCGLIB$$d87b5f2a");
Class localClass2;
Method[] tmp50_47 = ReflectUtils.findMethods(new String[] { "sayHello", "()Ljava/lang/String;" }, (localClass2 = Class.forName("com.selrain.DynamicProxy.HelloWorld")).getDeclaredMethods());
CGLIB$sayHello$0$Method = tmp50_47[0];
CGLIB$sayHello$0$Proxy = MethodProxy.create(localClass2, localClass1, "()Ljava/lang/String;", "sayHello", "CGLIB$sayHello$0");
tmp50_47;
Method[] tmp131_128 = ReflectUtils.findMethods(new String[] { "hashCode", "()I", "clone", "()Ljava/lang/Object;", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;" }, (localClass2 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$hashCode$1$Method = tmp131_128[0];
CGLIB$hashCode$1$Proxy = MethodProxy.create(localClass2, localClass1, "()I", "hashCode", "CGLIB$hashCode$1");
Method[] tmp151_131 = tmp131_128;
CGLIB$clone$2$Method = tmp151_131[1];
CGLIB$clone$2$Proxy = MethodProxy.create(localClass2, localClass1, "()Ljava/lang/Object;", "clone", "CGLIB$clone$2");
Method[] tmp171_151 = tmp151_131;
CGLIB$equals$3$Method = tmp171_151[2];
CGLIB$equals$3$Proxy = MethodProxy.create(localClass2, localClass1, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$3");
Method[] tmp191_171 = tmp171_151;
CGLIB$toString$4$Method = tmp191_171[3];
CGLIB$toString$4$Proxy = MethodProxy.create(localClass2, localClass1, "()Ljava/lang/String;", "toString", "CGLIB$toString$4");
tmp191_171;
} final String CGLIB$sayHello$0()
{
return super.sayHello();
}
//调用sayHello方法
public final String sayHello()
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
if (tmp17_14 != null)
//HelloWorldInterceptor 的intercept 方法
return (String)tmp17_14.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
return super.sayHello();
} final int CGLIB$hashCode$1()
{
return super.hashCode();
} public final int hashCode()
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
if (tmp17_14 != null)
{
Object tmp36_31 = tmp17_14.intercept(this, CGLIB$hashCode$1$Method, CGLIB$emptyArgs, CGLIB$hashCode$1$Proxy);
tmp36_31;
return tmp36_31 == null ? 0 : ((Number)tmp36_31).intValue();
}
return super.hashCode();
} final Object CGLIB$clone$2()
throws CloneNotSupportedException
{
return super.clone();
} protected final Object clone()
throws CloneNotSupportedException
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
if (tmp17_14 != null)
return tmp17_14.intercept(this, CGLIB$clone$2$Method, CGLIB$emptyArgs, CGLIB$clone$2$Proxy);
return super.clone();
} final boolean CGLIB$equals$3(Object paramObject)
{
return super.equals(paramObject);
} public final boolean equals(Object paramObject)
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
if (tmp17_14 != null)
{
Object tmp41_36 = tmp17_14.intercept(this, CGLIB$equals$3$Method, new Object[] { paramObject }, CGLIB$equals$3$Proxy);
tmp41_36;
return tmp41_36 == null ? false : ((Boolean)tmp41_36).booleanValue();
}
return super.equals(paramObject);
} final String CGLIB$toString$4()
{
return super.toString();
} public final String toString()
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
if (tmp17_14 != null)
return (String)tmp17_14.intercept(this, CGLIB$toString$4$Method, CGLIB$emptyArgs, CGLIB$toString$4$Proxy);
return super.toString();
} public static MethodProxy CGLIB$findMethodProxy(Signature paramSignature)
{
String tmp4_1 = paramSignature.toString();
switch (tmp4_1.hashCode())
{
case -508378822:
if (tmp4_1.equals("clone()Ljava/lang/Object;"))
return CGLIB$clone$2$Proxy;
break;
case 1459740658:
case 1826985398:
case 1913648695:
case 1984935277:
}
} public HelloWorld$$EnhancerByCGLIB$$d87b5f2a()
{
CGLIB$BIND_CALLBACKS(this);
} public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] paramArrayOfCallback)
{
CGLIB$THREAD_CALLBACKS.set(paramArrayOfCallback);
} public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] paramArrayOfCallback)
{
CGLIB$STATIC_CALLBACKS = paramArrayOfCallback;
} private static final void CGLIB$BIND_CALLBACKS(Object paramObject)
{
// Byte code:
// 0: aload_0
// 1: checkcast 2 com/selrain/DynamicProxy/HelloWorld$$EnhancerByCGLIB$$d87b5f2a
// 4: astore_1
// 5: aload_1
// 6: getfield 186 com/selrain/DynamicProxy/HelloWorld$$EnhancerByCGLIB$$d87b5f2a:CGLIB$BOUND Z
// 9: ifne +43 -> 52
// 12: aload_1
// 13: iconst_1
// 14: putfield 186 com/selrain/DynamicProxy/HelloWorld$$EnhancerByCGLIB$$d87b5f2a:CGLIB$BOUND Z
// 17: getstatic 27 com/selrain/DynamicProxy/HelloWorld$$EnhancerByCGLIB$$d87b5f2a:CGLIB$THREAD_CALLBACKS Ljava/lang/ThreadLocal;
// 20: invokevirtual 189 java/lang/ThreadLocal:get ()Ljava/lang/Object;
// 23: dup
// 24: ifnonnull +15 -> 39
// 27: pop
// 28: getstatic 184 com/selrain/DynamicProxy/HelloWorld$$EnhancerByCGLIB$$d87b5f2a:CGLIB$STATIC_CALLBACKS [Lnet/sf/cglib/proxy/Callback;
// 31: dup
// 32: ifnonnull +7 -> 39
// 35: pop
// 36: goto +16 -> 52
// 39: checkcast 190 [Lnet/sf/cglib/proxy/Callback;
// 42: aload_1
// 43: swap
// 44: iconst_0
// 45: aaload
// 46: checkcast 52 net/sf/cglib/proxy/MethodInterceptor
// 49: putfield 40 com/selrain/DynamicProxy/HelloWorld$$EnhancerByCGLIB$$d87b5f2a:CGLIB$CALLBACK_0 Lnet/sf/cglib/proxy/MethodInterceptor;
// 52: return
} public Object newInstance(Callback[] paramArrayOfCallback)
{
CGLIB$SET_THREAD_CALLBACKS(paramArrayOfCallback);
CGLIB$SET_THREAD_CALLBACKS(null);
return new d87b5f2a();
} public Object newInstance(Callback paramCallback)
{
CGLIB$SET_THREAD_CALLBACKS(new Callback[] { paramCallback });
CGLIB$SET_THREAD_CALLBACKS(null);
return new d87b5f2a();
} public Object newInstance(Class[] paramArrayOfClass, Object[] paramArrayOfObject, Callback[] paramArrayOfCallback)
{
CGLIB$SET_THREAD_CALLBACKS(paramArrayOfCallback);
Class[] tmp9_8 = paramArrayOfClass;
switch (tmp9_8.length)
{
case 0:
tmp9_8;
break;
default:
new d87b5f2a();
throw new IllegalArgumentException("Constructor not found");
}
CGLIB$SET_THREAD_CALLBACKS(null);
} public Callback getCallback(int paramInt)
{
CGLIB$BIND_CALLBACKS(this);
switch (paramInt)
{
case 0:
break;
}
return null;
} public void setCallback(int paramInt, Callback paramCallback)
{
switch (paramInt)
{
case 0:
this.CGLIB$CALLBACK_0 = ((MethodInterceptor)paramCallback);
break;
}
} public Callback[] getCallbacks()
{
CGLIB$BIND_CALLBACKS(this);
return new Callback[] { this.CGLIB$CALLBACK_0 };
} public void setCallbacks(Callback[] paramArrayOfCallback)
{
this.CGLIB$CALLBACK_0 = ((MethodInterceptor)paramArrayOfCallback[0]);
} static
{
CGLIB$STATICHOOK1();
}
}

MethodProxy 的invokeSuper方法:

public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
//调用代理类的CGLIB$sayHello$0方法
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
//生成fastClass类:其中f1代表target,(其type属性为target),f2代表生成的代理类;i1和i2分别代表方法sayHello和CGLIB$sayHello$0方法对应的索引位置
private void init()
{
if (fastClassInfo == null)
{
synchronized (initLock)
{
if (fastClassInfo == null)
{
CreateInfo ci = createInfo; FastClassInfo fci = new FastClassInfo();
fci.f1 = helper(ci, ci.c1);
fci.f2 = helper(ci, ci.c2);
fci.i1 = fci.f1.getIndex(sig1);
fci.i2 = fci.f2.getIndex(sig2);
fastClassInfo = fci;
createInfo = null;
}
}
}
}

代理类的CGLIB$sayHello$0方法:

final String CGLIB$sayHello$0()
{
//最终调用target的sayHello方法
return super.sayHello();
}

区别:

1、jdk动态代理生成的代理类和委托类实现了相同的接口

2、jdk动态代理利用了Java的反射机制,cglib动态代理利用了索引的方式直接调用委托类的方法,效率更高

参考:

1、占小狼的博客-说说cglib动态代理

2、饿了么物流技术-动态代理的实现与案例

Jdk动态代理和CGLIB动态代理大比拼的更多相关文章

  1. JDK动态代理和CGLib动态代理简单演示

    JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期间创建接口的代理实例. 一.首先我们进行JDK动态代理的演示. 现在我们有一个简单的业务接口Saying,如下: package te ...

  2. 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别。

    基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别. 我还是喜欢基于Schema风格的Spring事务管理,但也有很多人在用基于@Tras ...

  3. Spring -- <tx:annotation-driven>注解基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)的区别。

    借鉴:http://jinnianshilongnian.iteye.com/blog/1508018 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional ...

  4. Spring <tx:annotation-driven>注解 JDK动态代理和CGLIB动态代理 区别。

    基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别. 我还是喜欢基于Schema风格的Spring事务管理,但也有很多人在用基于@Tras ...

  5. java的静态代理、jdk动态代理和cglib动态代理

    Java的代理就是客户端不再直接和委托类打交道,而是通过一个中间层来访问,这个中间层就是代理.使用代理有两个好处,一是可以隐藏委托类的实现:二是可以实现客户与委托类之间的解耦,在不修改委托类代码的情况 ...

  6. jdk动态代理和cglib动态代理底层实现原理详细解析(cglib动态代理篇)

    代理模式是一种很常见的模式,本文主要分析cglib动态代理的过程 1. 举例 使用cglib代理需要引入两个包,maven的话包引入如下 <!-- https://mvnrepository.c ...

  7. 代理模式之静态代理,JDK动态代理和cglib动态代理

    代理模式,顾名思义,就是通过代理去完成某些功能.比如,你需要购买火车票,不想跑那么远到火车站售票窗口买,可以去附近的火车票代售点买,或者到携程等第三方网站买.这个时候,我们就把火车站叫做目标对象或者委 ...

  8. jdk动态代理和cglib动态代理的区别

    一.原理区别: java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. 而cglib动态代理是利用asm开源包,对代理对象类的class文件 ...

  9. jdk 动态代理和 cglib 动态代理

    原理区别: java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. 而cglib动态代理是利用asm开源包,对代理对象类的class文件加载 ...

  10. 动态代理:jdk动态代理和cglib动态代理

    /** * 动态代理类:先参考代理模式随笔,了解代理模式的概念,分为jdk动态代理和cglib,jdk动态代理是通过实现接口的方式创建代理类的,cglib是通过继承类的方式实现的代理类的 * jdk动 ...

随机推荐

  1. window切换Java版本原因

    查找Path环境变量的变量指向的目录,有一个Oracle目录存放着几个 java,javac等可执行文件,删除这个路径或文件就可以执行你指定的JavaHome目录拉 详情参考: https://blo ...

  2. ios http2客户端访问nginx失败bug

    我们将项目迁入腾讯云后,外网访问流量转发如下外网--->大禹BGP(BGPAntiDDoS)高防---->lbc(LoadBalance cluster)---->lb-----&g ...

  3. python 面向对象六 类属性和实例属性

    一.实例属性 Python是动态语言,根据类创建的实例可以任意绑定属性. >>> class Student(object): ... def __init__(self, name ...

  4. bzoj 1898: [Zjoi2005]Swamp 沼泽鳄鱼【dp+矩阵快速幂】

    注意到周期234的lcm只有12,也就是以12为周期,可以走的状态是一样的 所以先预处理出这12个状态的转移矩阵,乘起来,然后矩阵快速幂优化转移k/12次,然后剩下的次数暴力转移即可 #include ...

  5. 贪心/数学 Codeforces Round #212 (Div. 2) A. Two Semiknights Meet

    题目传送门 /* 贪心/数学:还以为是BFS,其实x1 + 4 * k = x2, y1 + 4 * l = y2 */ #include <cstdio> #include <al ...

  6. 转-解决Mysql ERROR 1045 (28000): Access denied for user 'root'@'localhost'问题

    ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)   Red Hat Enterpr ...

  7. 转 Dockerfile 常用指令 - 每天5分钟玩转 Docker 容器技术(16)

    是时候系统学习 Dockerfile 了. 下面列出了 Dockerfile 中最常用的指令,完整列表和说明可参看官方文档. FROM指定 base 镜像. MAINTAINER设置镜像的作者,可以是 ...

  8. 转】RDD与DataFrame的转换

    原博文出自于: http://www.cnblogs.com/namhwik/p/5967910.html RDD与DataFrame转换1. 通过反射的方式来推断RDD元素中的元数据.因为RDD本身 ...

  9. Elasticsearch--集群管理_别名&插件&更新API

    目录 使用索引别名 别名 创建别名 修改别名 合并命令 获取所有别名 移除别名 别名中过滤 别名和路由 Elasticsearch插件 基础知识 安装插件 移除插件 更新设置API 使用索引别名 通过 ...

  10. iOS programming Code Snippet Library

    iOS programming  Code Snippet Library  The freebie code comes from the code snippet library. 代码来自cod ...