JAVA动态代理
- 静态代理的代理关系在编译时就确定了,而动态代理的代理关系是在运行期确定的。静态代理实现简单,适合于代理类较少且确定的情况,而动态代理则给我们提供了更大的灵活性
- JDK原生动态代理是Java原生支持的,不需要任何外部依赖,但是它只能基于接口进行代理;CGLIB通过继承的方式进行代理,无论目标对象有没有实现接口都可以代理,但是无法处理final、private方法
- CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些
- jdk采用反射机制调用委托类的方法,cglib采用类似索引的方式直接调用委托类方法
标签(空格分隔): jdk动态代理 cglib
## jdk动态代理
jdk动态代理机制中,有两个重要的类或接口,一个是Proxy,另一个是
InvocationHandler
Proxy类
Proxy类是用来动态创建一个代理对象,经常使用newProxyInstance静态方法
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException
参数:
loader 类加载器
interfaces 真实类所拥有的所有接口的数组
h 调用处理器对象
InvocationHandler接口
InvocationHandler接口只有唯一一个invoke方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
参数:
proxy 代理类对象
method 调用真实类对象某个方法对应的method对象
args 调用真实类对象某个方法传入的参数
示例
1、主题接口
package com.example.ford.proxy;
public interface Subject {
String sayHello(String name);
String sayGoodBye();
}
2、 被代理类
package com.example.ford.proxy;
public class RealSubject implements Subject{
@Override
public String sayHello(String name) {
return "hello "+name;
}
@Override
public String sayGoodBye() {
return " good bye";
}
}
3、调用处理器
package com.example.ford.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TestInvocationHandler implements InvocationHandler{
private Subject subject;
public TestInvocationHandler(Subject subject){
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(proxy.getClass());
System.out.println("开始执行 "+method.getName());
Object returnValue = method.invoke(subject,args);
System.out.println("结束执行 "+method.getName());
return returnValue;
}
}
3、测试
package com.example.ford.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class TestMain {
public static void main(String[] args) {
Subject subject = new RealSubject();
InvocationHandler handler = new TestInvocationHandler(subject);
Class cls = subject.getClass();
ClassLoader loader = cls.getClassLoader();
Class[] interfaces = cls.getInterfaces();
Subject proxy = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);
String returnValue1 = proxy.sayHello("changfeng");
System.out.println(returnValue1);
String returnValue2 = proxy.sayGoodBye();
System.out.println(returnValue2);
}
}
测试结果
class com.sun.proxy.$Proxy0
开始执行 sayHello
结束执行 sayHello
hello changfeng
class com.sun.proxy.$Proxy0
开始执行 sayGoodBye
结束执行 sayGoodBye
good bye
原理分析
生成代理类类文件:
package com.example.ford.proxy;
import sun.misc.ProxyGenerator;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class JDKProxyTest {
public static void main(String[] args){
Subject subject = new RealSubject();
InvocationHandler handler = new TestInvocationHandler(subject);
Class cls = subject.getClass();
ClassLoader loader = cls.getClassLoader();
Class[] interfaces = cls.getInterfaces();
Subject proxy = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);
createProxyClassFile();
}
private static void createProxyClassFile(){
String name = "ProxySubject";
byte[] data = ProxyGenerator.generateProxyClass(name,new Class[]{Subject.class});
FileOutputStream out =null;
try {
out = new FileOutputStream(name+".class");
System.out.println((new File("hello")).getAbsolutePath());
out.write(data);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(null!=out) try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
利用jd-gui反编译代理类class文件,可以发现最终生成的代理类继承Proxy类、实现Subject接口,代理类实现了Subject接口的sayHello方法、sayGoodBye方法,在实现Subject接口方法的内部,通过反射调用了InvocationHandlerImpl的invoke方法
import com.example.ford.proxy.Subject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class ProxySubject
extends Proxy
implements Subject
{
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m4;
private static Method m0;
public ProxySubject(InvocationHandler paramInvocationHandler)
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String sayHello(String paramString)
{
try
{
return (String)this.h.invoke(this, m3, new Object[] { paramString });
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String sayGoodBye()
{
try
{
return (String)this.h.invoke(this, m4, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("com.example.ford.proxy.Subject").getMethod("sayHello", new Class[] { Class.forName("java.lang.String") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m4 = Class.forName("com.example.ford.proxy.Subject").getMethod("sayGoodBye", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
注意:对于从Object中继承的方法,JDK Proxy会把hashCode()、equals()、toString()这三个非接口方法转发给InvocationHandler,其余的Object方法则不会转发
## cglib动态代理
cglib动态代理必须实现MethodInterceptor接口
MethodInterceptor接口
package org.springframework.cglib.proxy;
import java.lang.reflect.Method;
public interface MethodInterceptor extends Callback {
Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
参数1 代理对象
参数2 方法对象
参数3 方法参数
参数4 方法对应的
}
示例
package com.example.ford.proxy;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy implements MethodInterceptor{
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class cls){
enhancer.setSuperclass(cls);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println(o.getClass());
System.out.println("开始执行 "+method.getName());
//我们一般使用proxy.invokeSuper(obj,args)方法。这个很好理解,就是执行原始类的方法。还有一个方法proxy.invoke(obj,args),这是执行生成子类的方法。
//如果传入的obj就是子类的话,会发生内存溢出,因为子类的方法不停地进入intercept方法,而这个方法又去调用子类的方法,两个方法直接循环调用了。
Object returnValue = methodProxy.invokeSuper(o,objects);
//Object returnValue = methodProxy.invoke(o,objects);
System.out.println("结束执行 "+method.getName());
return returnValue;
}
public static void main(String[] args){
CglibProxy cglibProxy = new CglibProxy();
RealSubject realSubject = (RealSubject)cglibProxy.getProxy(RealSubject.class);
Object returnValue1 = realSubject.sayHello("changfeng");
System.out.println(returnValue1);
Object returnValue2 = realSubject.sayGoodBye();
System.out.println(returnValue2);
}
}
注意:对于从Object中继承的方法,CGLIB代理也会进行代理,如hashCode()、equals()、toString()等,但是getClass()、wait()等方法不会,因为它是final方法,CGLIB无法代理
注意:既然是继承就不得不考虑final的问题。我们知道final类型不能有子类,所以CGLIB不能代理final类型,遇到这种情况会抛出类似如下异常:
java.lang.IllegalArgumentException: Cannot subclass final class cglib.HelloConcrete
注意:同样的,final方法是不能重载的,所以也不能通过CGLIB代理,遇到这种情况不会抛异常,而是会跳过final方法只代理其他方法。
源码分析
通过以下方式可以生成代理类class文件 System.setProperty(DebuggingClassWriter.DEBUGLOCATIONPROPERTY, "C:\\Code\\whywhy\\target\\classes\\zzzzzz")
用jd-gui反编译代理类
package com.example.ford.proxy;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class RealSubject$$EnhancerByCGLIB$$6a387257
extends RealSubject
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$sayGoodBye$1$Method;
private static final MethodProxy CGLIB$sayGoodBye$1$Proxy;
private static final Method CGLIB$equals$2$Method;
private static final MethodProxy CGLIB$equals$2$Proxy;
private static final Method CGLIB$toString$3$Method;
private static final MethodProxy CGLIB$toString$3$Proxy;
private static final Method CGLIB$hashCode$4$Method;
private static final MethodProxy CGLIB$hashCode$4$Proxy;
private static final Method CGLIB$clone$5$Method;
private static final MethodProxy CGLIB$clone$5$Proxy;
/* Error */
static void CGLIB$STATICHOOK1()
{
// Byte code:
// 0: new 22 java/lang/ThreadLocal
// 3: dup
// 4: invokespecial 25 java/lang/ThreadLocal:<init> ()V
// 7: putstatic 27 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$THREAD_CALLBACKS Ljava/lang/ThreadLocal;
// 10: iconst_0
// 11: anewarray 48 java/lang/Object
// 14: putstatic 69 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$emptyArgs [Ljava/lang/Object;
// 17: ldc -108
// 19: invokestatic 154 java/lang/Class:forName (Ljava/lang/String;)Ljava/lang/Class;
// 22: astore_0
// 23: iconst_4
// 24: anewarray 58 java/lang/String
// 27: dup
// 28: iconst_0
// 29: ldc -101
// 31: aastore
// 32: dup
// 33: iconst_1
// 34: ldc -100
// 36: aastore
// 37: dup
// 38: iconst_2
// 39: ldc -99
// 41: aastore
// 42: dup
// 43: iconst_3
// 44: ldc -98
// 46: aastore
// 47: ldc -96
// 49: invokestatic 154 java/lang/Class:forName (Ljava/lang/String;)Ljava/lang/Class;
// 52: dup
// 53: astore_1
// 54: invokevirtual 164 java/lang/Class:getDeclaredMethods ()[Ljava/lang/reflect/Method;
// 57: invokestatic 170 org/springframework/cglib/core/ReflectUtils:findMethods ([Ljava/lang/String;[Ljava/lang/reflect/Method;)[Ljava/lang/reflect/Method;
// 60: dup
// 61: iconst_0
// 62: aaload
// 63: putstatic 46 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$sayHello$0$Method Ljava/lang/reflect/Method;
// 66: aload_1
// 67: aload_0
// 68: ldc -100
// 70: ldc -101
// 72: ldc -85
// 74: invokestatic 177 org/springframework/cglib/proxy/MethodProxy:create (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/springframework/cglib/proxy/MethodProxy;
// 77: putstatic 50 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$sayHello$0$Proxy Lorg/springframework/cglib/proxy/MethodProxy;
// 80: dup
// 81: iconst_1
// 82: aaload
// 83: putstatic 67 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$sayGoodBye$1$Method Ljava/lang/reflect/Method;
// 86: aload_1
// 87: aload_0
// 88: ldc -98
// 90: ldc -99
// 92: ldc -78
// 94: invokestatic 177 org/springframework/cglib/proxy/MethodProxy:create (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/springframework/cglib/proxy/MethodProxy;
// 97: putstatic 71 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$sayGoodBye$1$Proxy Lorg/springframework/cglib/proxy/MethodProxy;
// 100: pop
// 101: bipush 8
// 103: anewarray 58 java/lang/String
// 106: dup
// 107: iconst_0
// 108: ldc -77
// 110: aastore
// 111: dup
// 112: iconst_1
// 113: ldc -76
// 115: aastore
// 116: dup
// 117: iconst_2
// 118: ldc -75
// 120: aastore
// 121: dup
// 122: iconst_3
// 123: ldc -98
// 125: aastore
// 126: dup
// 127: iconst_4
// 128: ldc -74
// 130: aastore
// 131: dup
// 132: iconst_5
// 133: ldc -73
// 135: aastore
// 136: dup
// 137: bipush 6
// 139: ldc -72
// 141: aastore
// 142: dup
// 143: bipush 7
// 145: ldc -71
// 147: aastore
// 148: ldc -69
// 150: invokestatic 154 java/lang/Class:forName (Ljava/lang/String;)Ljava/lang/Class;
// 153: dup
// 154: astore_1
// 155: invokevirtual 164 java/lang/Class:getDeclaredMethods ()[Ljava/lang/reflect/Method;
// 158: invokestatic 170 org/springframework/cglib/core/ReflectUtils:findMethods ([Ljava/lang/String;[Ljava/lang/reflect/Method;)[Ljava/lang/reflect/Method;
// 161: dup
// 162: iconst_0
// 163: aaload
// 164: putstatic 80 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$equals$2$Method Ljava/lang/reflect/Method;
// 167: aload_1
// 168: aload_0
// 169: ldc -76
// 171: ldc -77
// 173: ldc -68
// 175: invokestatic 177 org/springframework/cglib/proxy/MethodProxy:create (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/springframework/cglib/proxy/MethodProxy;
// 178: putstatic 82 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$equals$2$Proxy Lorg/springframework/cglib/proxy/MethodProxy;
// 181: dup
// 182: iconst_1
// 183: aaload
// 184: putstatic 96 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$toString$3$Method Ljava/lang/reflect/Method;
// 187: aload_1
// 188: aload_0
// 189: ldc -98
// 191: ldc -75
// 193: ldc -67
// 195: invokestatic 177 org/springframework/cglib/proxy/MethodProxy:create (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/springframework/cglib/proxy/MethodProxy;
// 198: putstatic 98 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$toString$3$Proxy Lorg/springframework/cglib/proxy/MethodProxy;
// 201: dup
// 202: iconst_2
// 203: aaload
// 204: putstatic 107 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$hashCode$4$Method Ljava/lang/reflect/Method;
// 207: aload_1
// 208: aload_0
// 209: ldc -73
// 211: ldc -74
// 213: ldc -66
// 215: invokestatic 177 org/springframework/cglib/proxy/MethodProxy:create (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/springframework/cglib/proxy/MethodProxy;
// 218: putstatic 109 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$hashCode$4$Proxy Lorg/springframework/cglib/proxy/MethodProxy;
// 221: dup
// 222: iconst_3
// 223: aaload
// 224: putstatic 125 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$clone$5$Method Ljava/lang/reflect/Method;
// 227: aload_1
// 228: aload_0
// 229: ldc -71
// 231: ldc -72
// 233: ldc -65
// 235: invokestatic 177 org/springframework/cglib/proxy/MethodProxy:create (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/springframework/cglib/proxy/MethodProxy;
// 238: putstatic 127 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$clone$5$Proxy Lorg/springframework/cglib/proxy/MethodProxy;
// 241: pop
// 242: return
// 243: athrow
}
final String CGLIB$sayHello$0(String paramString)
{
return super.sayHello(paramString);
}
public final String sayHello(String paramString)
{
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$sayHello$0$Method, new Object[] { paramString }, CGLIB$sayHello$0$Proxy);
}
return super.sayHello(paramString);
}
final String CGLIB$sayGoodBye$1()
{
return super.sayGoodBye();
}
public final String sayGoodBye()
{
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$sayGoodBye$1$Method, CGLIB$emptyArgs, CGLIB$sayGoodBye$1$Proxy);
}
return super.sayGoodBye();
}
final boolean CGLIB$equals$2(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$2$Method, new Object[] { paramObject }, CGLIB$equals$2$Proxy);
tmp41_36;
return tmp41_36 == null ? false : ((Boolean)tmp41_36).booleanValue();
}
return super.equals(paramObject);
}
final String CGLIB$toString$3()
{
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$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy);
}
return super.toString();
}
final int CGLIB$hashCode$4()
{
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$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy);
tmp36_31;
return tmp36_31 == null ? 0 : ((Number)tmp36_31).intValue();
}
return super.hashCode();
}
final Object CGLIB$clone$5()
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$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy);
}
return super.clone();
}
/* Error */
public static MethodProxy CGLIB$findMethodProxy(org.springframework.cglib.core.Signature arg0)
{
// Byte code:
// 0: aload_0
// 1: invokevirtual 130 java/lang/Object:toString ()Ljava/lang/String;
// 4: dup
// 5: invokevirtual 131 java/lang/Object:hashCode ()I
// 8: lookupswitch default:+132->140, -1816210712:+60->68, -508378822:+72->80, 1577955665:+84->92, 1826985398:+96->104, 1913648695:+108->116, 1984935277:+120->128
// 68: ldc -123
// 70: invokevirtual 134 java/lang/Object:equals (Ljava/lang/Object;)Z
// 73: ifeq +68 -> 141
// 76: getstatic 50 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$sayHello$0$Proxy Lorg/springframework/cglib/proxy/MethodProxy;
// 79: areturn
// 80: ldc -120
// 82: invokevirtual 134 java/lang/Object:equals (Ljava/lang/Object;)Z
// 85: ifeq +56 -> 141
// 88: getstatic 127 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$clone$5$Proxy Lorg/springframework/cglib/proxy/MethodProxy;
// 91: areturn
// 92: ldc -118
// 94: invokevirtual 134 java/lang/Object:equals (Ljava/lang/Object;)Z
// 97: ifeq +44 -> 141
// 100: getstatic 71 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$sayGoodBye$1$Proxy Lorg/springframework/cglib/proxy/MethodProxy;
// 103: areturn
// 104: ldc -116
// 106: invokevirtual 134 java/lang/Object:equals (Ljava/lang/Object;)Z
// 109: ifeq +32 -> 141
// 112: getstatic 82 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$equals$2$Proxy Lorg/springframework/cglib/proxy/MethodProxy;
// 115: areturn
// 116: ldc -114
// 118: invokevirtual 134 java/lang/Object:equals (Ljava/lang/Object;)Z
// 121: ifeq +20 -> 141
// 124: getstatic 98 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$toString$3$Proxy Lorg/springframework/cglib/proxy/MethodProxy;
// 127: areturn
// 128: ldc -112
// 130: invokevirtual 134 java/lang/Object:equals (Ljava/lang/Object;)Z
// 133: ifeq +8 -> 141
// 136: getstatic 109 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$hashCode$4$Proxy Lorg/springframework/cglib/proxy/MethodProxy;
// 139: areturn
// 140: pop
// 141: aconst_null
// 142: areturn
}
public RealSubject$$EnhancerByCGLIB$$6a387257()
{
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)
{
6a387257 local6a387257 = (6a387257)paramObject;
if (!local6a387257.CGLIB$BOUND)
{
local6a387257.CGLIB$BOUND = true;
Object tmp23_20 = CGLIB$THREAD_CALLBACKS.get();
if (tmp23_20 == null)
{
tmp23_20;
CGLIB$STATIC_CALLBACKS;
}
local6a387257.CGLIB$CALLBACK_0 = (tmp31_28 == null ? tmp31_28 : (MethodInterceptor)((Callback[])tmp23_20)[0]);
}
}
public Object newInstance(Callback[] paramArrayOfCallback)
{
CGLIB$SET_THREAD_CALLBACKS(paramArrayOfCallback);
CGLIB$SET_THREAD_CALLBACKS(null);
return new 6a387257();
}
public Object newInstance(Callback paramCallback)
{
CGLIB$SET_THREAD_CALLBACKS(new Callback[] { paramCallback });
CGLIB$SET_THREAD_CALLBACKS(null);
return new 6a387257();
}
/* Error */
public Object newInstance(Class[] arg1, Object[] arg2, Callback[] arg3)
{
// Byte code:
// 0: aload_3
// 1: invokestatic 210 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$SET_THREAD_CALLBACKS ([Lorg/springframework/cglib/proxy/Callback;)V
// 4: new 2 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257
// 7: dup
// 8: aload_1
// 9: dup
// 10: arraylength
// 11: tableswitch default:+24->35, 0:+17->28
// 28: pop
// 29: invokespecial 211 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:<init> ()V
// 32: goto +17 -> 49
// 35: goto +3 -> 38
// 38: pop
// 39: new 217 java/lang/IllegalArgumentException
// 42: dup
// 43: ldc -37
// 45: invokespecial 222 java/lang/IllegalArgumentException:<init> (Ljava/lang/String;)V
// 48: athrow
// 49: aconst_null
// 50: invokestatic 210 com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$SET_THREAD_CALLBACKS ([Lorg/springframework/cglib/proxy/Callback;)V
// 53: areturn
}
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 {}
}
每个被代理的方法都对应一个MethodProxy对象,methodProxy.invokeSuper方法最终调用委托类的add方法
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
单看invokeSuper方法的实现,似乎看不出委托类add方法调用,在MethodProxy实现中,通过FastClassInfo维护了委托类和代理类的FastClass。
private static class FastClassInfo {
FastClass f1;
FastClass f2;
int i1;
int i2;
}
以sayHello方法的methodProxy为例,f1指向委托类对象,f2指向代理类对象,i1和i2分别是方法sayHello和CGLIB$sayHello$0在对象中索引位置。
FastClass实现机制
FastClass其实就是对Class对象进行特殊处理,提出下标概念index,通过索引保存方法的引用信息,将原先的反射调用,转化为方法的直接调用,从而体现所谓的fast,下面通过一个例子了解一下FastClass的实现机制。
1、定义原类
class Test {
public void f(){
System.out.println("f method");
}
public void g(){
System.out.println("g method");
}
}
2、定义Fast类
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;
}
}
在FastTest中有两个方法,getIndex中对Test类的每个方法根据hash建立索引,invoke根据指定的索引,直接调用目标方法,避免了反射调用。所以当调用methodProxy.invokeSuper方法时,实际上是调用代理类的CGLIB$sayHello$0方法,CGLIB$sayHello$0直接调用了委托类的sayHello方法