Jdk动态代理和CGLIB动态代理大比拼
前言:
这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动态代理利用了索引的方式直接调用委托类的方法,效率更高
参考: