Java动态代理机制详解
静态代理模式固然在访问无法访问的资源、增强现有接口业务功能方面有很大的优点,但是大量使用静态代理,会使我们系统内的类规模增大,并且不易维护。 而且由于Proxy和RealSubject的功能本质上是相同的,Proxy只是起到了中介的作用,这代理在系统中的存在,导致系统结构比较臃肿和松散。
为了解决这个问题,就有了动态创建Proxy的想法,在运行状态中,根据Subject和RealSubject,动态的创建一个Proxy,用完之后,就销毁。 这就可以避免Proxy角色的class在系统中的冗杂问题了。
public interface IFly {
void fly();
}
public interface IRun {
void run();
}
public class Person implements IRun, IFly {
@Override
public void fly() {
System.out.println("Person.fly");
}
@Override
public void run() {
System.out.println("Person.run");
}
}
public class ProxyUtils {
public static void generateClassFile(Class clazz, String proxyName) {
// 根据类信息和提供的代理类名称,生成字节码
byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
String paths = clazz.getResource(".").getPath();
FileOutputStream out = null;
try {
// 写入硬盘中
out = new FileOutputStream(paths + proxyName + ".class");
out.write(classFile);
out.flush();
} catch (Exception e) {
} finally {
try {
out.close();
} catch (Exception e) {
}
}
}
public static void main(String[] args) {
// 将在同级目录下生成 PersonProxy.class 文件
// 用反编译工具打开如下
ProxyUtils.generateClassFile(Person.class, "PersonProxy");
}
}
JDK动态代理机制,接口
过程如下
- 获取 RealSubject 的接口列表;
- 确定要生成的代理类的类名,默认为:com.sun.proxy.$ProxyXXXX
- 根据需要实现的接口信息,在代码中动态创建该Proxy类的字节码
- 将对应的字节码转换为对应的class对象
- 创建InvocationHandler 实例handler,用来处理Proxy所有方法调用
- Proxy的class对象以创建的handler对象为参数,实例化一个Proxy对象
// 生成class文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
Object o = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{IFly.class, IRun.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(new Person(), args);
}
});
IFly fly = (IFly) o;
fly.fly();
import com.junhc.common.proxy.IFly;
import com.junhc.common.proxy.IRun;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class PersonProxy
extends Proxy
implements IRun, IFly
{
private static Method m1;
private static Method m3;
private static Method m4;
private static Method m0;
private static Method m2;
public PersonProxy(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 void run()
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void fly()
{
try
{
this.h.invoke(this, m4, null);
return;
}
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);
}
}
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);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("com.junhc.common.proxy.IRun").getMethod("run", new Class[0]);
m4 = Class.forName("com.junhc.common.proxy.IFly").getMethod("fly", new Class[0]);
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());
}
}
}
- 继承 java.lang.reflect.Proxy,实现了 IFly、IRun 接口
- 类中所有的方法都是 final
- 所有方法的实现都统一使用 InvocationHandler 的 invoke 方法
CGLIB 动态代理机制,类继承
过程如下
- 查找A上的所有非final的public类型的方法定义
- 将这些方法的定义转换成字节码
- 将组成的字节码转换成相应的代理的class对象
- 实现 MethodInterceptor接口,用来处理对代理类上所有方法的请求(这个接口和JDK动态代理InvocationHandler的功能和角色是一样的)
String path = Person.class.getResource(".").getPath();
// 生成class文件
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, path);
Enhancer enhancer = new Enhancer();
// 设置要创建动态代理的类
enhancer.setSuperclass(Person.class);
// 设置回调,对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实行intercept()方法进行拦截
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable {
return proxy.invokeSuper(o, args);
}
});
Object o = enhancer.create();
IFly fly = (IFly) o;
fly.fly();
package com.junhc.common.proxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class Person$$EnhancerByCGLIB$$dcfb2f4d
extends Person
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$run$0$Method;
private static final MethodProxy CGLIB$run$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$fly$1$Method;
private static final MethodProxy CGLIB$fly$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/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$THREAD_CALLBACKS Ljava/lang/ThreadLocal;
// 10: iconst_0
// 11: anewarray 76 java/lang/Object
// 14: putstatic 47 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$emptyArgs [Ljava/lang/Object;
// 17: ldc -109
// 19: invokestatic 153 java/lang/Class:forName (Ljava/lang/String;)Ljava/lang/Class;
// 22: astore_0
// 23: iconst_4
// 24: anewarray 97 java/lang/String
// 27: dup
// 28: iconst_0
// 29: ldc -102
// 31: aastore
// 32: dup
// 33: iconst_1
// 34: ldc -101
// 36: aastore
// 37: dup
// 38: iconst_2
// 39: ldc -100
// 41: aastore
// 42: dup
// 43: iconst_3
// 44: ldc -101
// 46: aastore
// 47: ldc -98
// 49: invokestatic 153 java/lang/Class:forName (Ljava/lang/String;)Ljava/lang/Class;
// 52: dup
// 53: astore_1
// 54: invokevirtual 162 java/lang/Class:getDeclaredMethods ()[Ljava/lang/reflect/Method;
// 57: invokestatic 168 net/sf/cglib/core/ReflectUtils:findMethods ([Ljava/lang/String;[Ljava/lang/reflect/Method;)[Ljava/lang/reflect/Method;
// 60: dup
// 61: iconst_0
// 62: aaload
// 63: putstatic 45 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$run$0$Method Ljava/lang/reflect/Method;
// 66: aload_1
// 67: aload_0
// 68: ldc -101
// 70: ldc -102
// 72: ldc -87
// 74: invokestatic 175 net/sf/cglib/proxy/MethodProxy:create (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lnet/sf/cglib/proxy/MethodProxy;
// 77: putstatic 49 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$run$0$Proxy Lnet/sf/cglib/proxy/MethodProxy;
// 80: dup
// 81: iconst_1
// 82: aaload
// 83: putstatic 63 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$fly$1$Method Ljava/lang/reflect/Method;
// 86: aload_1
// 87: aload_0
// 88: ldc -101
// 90: ldc -100
// 92: ldc -80
// 94: invokestatic 175 net/sf/cglib/proxy/MethodProxy:create (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lnet/sf/cglib/proxy/MethodProxy;
// 97: putstatic 65 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$fly$1$Proxy Lnet/sf/cglib/proxy/MethodProxy;
// 100: pop
// 101: bipush 8
// 103: anewarray 97 java/lang/String
// 106: dup
// 107: iconst_0
// 108: ldc -79
// 110: aastore
// 111: dup
// 112: iconst_1
// 113: ldc -78
// 115: aastore
// 116: dup
// 117: iconst_2
// 118: ldc -77
// 120: aastore
// 121: dup
// 122: iconst_3
// 123: ldc -76
// 125: aastore
// 126: dup
// 127: iconst_4
// 128: ldc -75
// 130: aastore
// 131: dup
// 132: iconst_5
// 133: ldc -74
// 135: aastore
// 136: dup
// 137: bipush 6
// 139: ldc -73
// 141: aastore
// 142: dup
// 143: bipush 7
// 145: ldc -72
// 147: aastore
// 148: ldc -70
// 150: invokestatic 153 java/lang/Class:forName (Ljava/lang/String;)Ljava/lang/Class;
// 153: dup
// 154: astore_1
// 155: invokevirtual 162 java/lang/Class:getDeclaredMethods ()[Ljava/lang/reflect/Method;
// 158: invokestatic 168 net/sf/cglib/core/ReflectUtils:findMethods ([Ljava/lang/String;[Ljava/lang/reflect/Method;)[Ljava/lang/reflect/Method;
// 161: dup
// 162: iconst_0
// 163: aaload
// 164: putstatic 74 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$equals$2$Method Ljava/lang/reflect/Method;
// 167: aload_1
// 168: aload_0
// 169: ldc -78
// 171: ldc -79
// 173: ldc -69
// 175: invokestatic 175 net/sf/cglib/proxy/MethodProxy:create (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lnet/sf/cglib/proxy/MethodProxy;
// 178: putstatic 78 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$equals$2$Proxy Lnet/sf/cglib/proxy/MethodProxy;
// 181: dup
// 182: iconst_1
// 183: aaload
// 184: putstatic 93 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$toString$3$Method Ljava/lang/reflect/Method;
// 187: aload_1
// 188: aload_0
// 189: ldc -76
// 191: ldc -77
// 193: ldc -68
// 195: invokestatic 175 net/sf/cglib/proxy/MethodProxy:create (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lnet/sf/cglib/proxy/MethodProxy;
// 198: putstatic 95 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$toString$3$Proxy Lnet/sf/cglib/proxy/MethodProxy;
// 201: dup
// 202: iconst_2
// 203: aaload
// 204: putstatic 106 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$hashCode$4$Method Ljava/lang/reflect/Method;
// 207: aload_1
// 208: aload_0
// 209: ldc -74
// 211: ldc -75
// 213: ldc -67
// 215: invokestatic 175 net/sf/cglib/proxy/MethodProxy:create (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lnet/sf/cglib/proxy/MethodProxy;
// 218: putstatic 108 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$hashCode$4$Proxy Lnet/sf/cglib/proxy/MethodProxy;
// 221: dup
// 222: iconst_3
// 223: aaload
// 224: putstatic 124 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$clone$5$Method Ljava/lang/reflect/Method;
// 227: aload_1
// 228: aload_0
// 229: ldc -72
// 231: ldc -73
// 233: ldc -66
// 235: invokestatic 175 net/sf/cglib/proxy/MethodProxy:create (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lnet/sf/cglib/proxy/MethodProxy;
// 238: putstatic 126 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$clone$5$Proxy Lnet/sf/cglib/proxy/MethodProxy;
// 241: pop
// 242: return
// 243: athrow
}
final void CGLIB$run$0()
{
super.run();
}
public final void run()
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
if (this.CGLIB$CALLBACK_0 != null) {
return;
}
super.run();
}
final void CGLIB$fly$1()
{
super.fly();
}
public final void fly()
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
if (this.CGLIB$CALLBACK_0 != null) {
return;
}
super.fly();
}
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(net.sf.cglib.core.Signature arg0)
{
// Byte code:
// 0: aload_0
// 1: invokevirtual 129 java/lang/Object:toString ()Ljava/lang/String;
// 4: dup
// 5: invokevirtual 130 java/lang/Object:hashCode ()I
// 8: lookupswitch default:+132->140, -1271409118:+60->68, -919875318:+72->80, -508378822:+84->92, 1826985398:+96->104, 1913648695:+108->116, 1984935277:+120->128
// 68: ldc -124
// 70: invokevirtual 133 java/lang/Object:equals (Ljava/lang/Object;)Z
// 73: ifeq +68 -> 141
// 76: getstatic 65 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$fly$1$Proxy Lnet/sf/cglib/proxy/MethodProxy;
// 79: areturn
// 80: ldc -121
// 82: invokevirtual 133 java/lang/Object:equals (Ljava/lang/Object;)Z
// 85: ifeq +56 -> 141
// 88: getstatic 49 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$run$0$Proxy Lnet/sf/cglib/proxy/MethodProxy;
// 91: areturn
// 92: ldc -119
// 94: invokevirtual 133 java/lang/Object:equals (Ljava/lang/Object;)Z
// 97: ifeq +44 -> 141
// 100: getstatic 126 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$clone$5$Proxy Lnet/sf/cglib/proxy/MethodProxy;
// 103: areturn
// 104: ldc -117
// 106: invokevirtual 133 java/lang/Object:equals (Ljava/lang/Object;)Z
// 109: ifeq +32 -> 141
// 112: getstatic 78 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$equals$2$Proxy Lnet/sf/cglib/proxy/MethodProxy;
// 115: areturn
// 116: ldc -115
// 118: invokevirtual 133 java/lang/Object:equals (Ljava/lang/Object;)Z
// 121: ifeq +20 -> 141
// 124: getstatic 95 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$toString$3$Proxy Lnet/sf/cglib/proxy/MethodProxy;
// 127: areturn
// 128: ldc -113
// 130: invokevirtual 133 java/lang/Object:equals (Ljava/lang/Object;)Z
// 133: ifeq +8 -> 141
// 136: getstatic 108 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$hashCode$4$Proxy Lnet/sf/cglib/proxy/MethodProxy;
// 139: areturn
// 140: pop
// 141: aconst_null
// 142: areturn
}
public Person$$EnhancerByCGLIB$$dcfb2f4d()
{
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)
{
dcfb2f4d localdcfb2f4d = (dcfb2f4d)paramObject;
if (!localdcfb2f4d.CGLIB$BOUND)
{
localdcfb2f4d.CGLIB$BOUND = true;
Object tmp23_20 = CGLIB$THREAD_CALLBACKS.get();
if (tmp23_20 == null)
{
tmp23_20;
CGLIB$STATIC_CALLBACKS;
}
localdcfb2f4d.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 dcfb2f4d();
}
public Object newInstance(Callback paramCallback)
{
CGLIB$SET_THREAD_CALLBACKS(new Callback[] { paramCallback });
CGLIB$SET_THREAD_CALLBACKS(null);
return new dcfb2f4d();
}
/* Error */
public Object newInstance(Class[] arg1, Object[] arg2, Callback[] arg3)
{
// Byte code:
// 0: aload_3
// 1: invokestatic 209 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$SET_THREAD_CALLBACKS ([Lnet/sf/cglib/proxy/Callback;)V
// 4: new 2 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d
// 7: dup
// 8: aload_1
// 9: dup
// 10: arraylength
// 11: tableswitch default:+24->35, 0:+17->28
// 28: pop
// 29: invokespecial 210 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:<init> ()V
// 32: goto +17 -> 49
// 35: goto +3 -> 38
// 38: pop
// 39: new 216 java/lang/IllegalArgumentException
// 42: dup
// 43: ldc -38
// 45: invokespecial 221 java/lang/IllegalArgumentException:<init> (Ljava/lang/String;)V
// 48: athrow
// 49: aconst_null
// 50: invokestatic 209 com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$SET_THREAD_CALLBACKS ([Lnet/sf/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 {}
}
- 代理类Person\(EnhancerByCGLIB\)dcfb2f4d继承委托类Person,且委托类的final方法不能被代理
- 代理类为每个委托方法都生成两个方法,一个是重写方法、一个是CGLIB$run$0方法,该方法直接调用委托类的run方法
- 当执行代理对象的run方法时,会先判断是否存在实现了MethodInterceptor接口的对象cglib$CALLBACK_0,如果存在,则调用MethodInterceptor对象的intercept方法:
public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) {
System.out.println("Before:" + method);
Object object = proxy.invokeSuper(obj, arg);
System.out.println("After:" + method);
return object;
}
- 参数分别为:
- 1、代理对象;
- 2、委托类方法;
- 3、方法参数;
- 4、代理方法的MethodProxy对象。
每个被代理的方法都对应一个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;
}
以run方法的methodProxy为例,f1指向委托类对象,f2指向代理类对象,i1和i2分别是方法run和CGLIB$run$0在对象中索引位置。
FastClass实现机制
FastClass其实就是对Class对象进行特殊处理,提出下标概念index,通过索引保存方法的引用信息,将原先的反射调用,转化为方法的直接调用,从而体现所谓的fast,下面通过一个例子了解一下FastClass的实现机制。
class Test {
public void f(){
System.out.println("f method");
}
public void g(){
System.out.println("g method");
}
}
```vim
2、定义Fast类
```vim
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$run$0方法,CGLIB$run$0直接调用了委托类的run方法。
JDK和CGLIB动态代理实现的区别
- JDK动态代理生成的代理类和委托类实现了相同的接口
- CGLIB动态代理中生成的字节码更加复杂,生成的代理类是委托类的子类,且不能处理被final关键字修饰的方法
- JDK采用反射机制调用委托类的方法,CGLIB采用类似索引的方式直接调用委托类方法
使用 HSDB JVM运行时数据可视化工具获取动态生成的class文件
- java -cp ‘%JAVA_HOME%/lib/sa-jdi.jar’ sun.jvm.hotspot.HSDB
- 点击 File 菜单, Attach to HotSpot process, 输入Java程序的进程号PID
- 点击 Tools 菜单, Class Browser, 输入包名
- 点击 Create .class File