您的位置:首页 > 编程语言 > Java开发

JDK动态代理与CGLIB动态代理应用及源码解析

2018-03-15 13:40 731 查看

代理模式

代理模式:为其他对象提供一种代理以控制对这个对象的访问。

代理模式中有三种角色:Subject抽象主题角色、RealSubject真实主题角色、Proxy代理主题角色。Subject描述了业务行为,RealSubject执行具体的业务逻辑,Proxy代理会拦截对RealSubject对象方法的调用,并在方法调用前后做预处理以及一些善后工作。

代理模式可以很好地在不侵入原代码的情况下,拓展原来的功能。

下图为Proxy模式的静态类图:



下图为Proxy模式的调用关系:



动态代理

静态代理由于硬编码,难以应对真实对象和调用方法灵活多变的情况,动态代理则对这些场景应付自如。

动态代理主要有两种实现方式:1、JDK自带的Proxy 2、CGLIB字节码生成库

基于JDK的动态代理

基于JDK的动态代理关键在于两个类:InvocationHandler和Proxy。

其主要实现逻辑是,由InvocationHandler定义方法执行前后的增强逻辑,由Proxy类去生成一个继承自Proxy并且实现了真实对象接口的新对象–代理对象,对该代理对象的方法调用经由InvocationHandler拦截,执行增强逻辑和调用真实对象执行业务逻辑。

下面我们先看一个例子:

定义接口:

public interface UserService {
public String getName(int id);

public Integer getAge(int id);
}


定义真实对象:

public class UserServiceImpl implements UserService {

public UserServiceImpl() {
}

@Override
public String getName(int id) {
System.out.println("---getName---");
return "John";
}

@Override
public Integer getAge(int id) {
System.out.println("---getAge---");
return 10;
}

}


定义InvocationHandler:

public class MyInvocationHandler implements InvocationHandler {
private Object target;

public MyInvocationHandler(Object target) {
this.target = target;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("getName")) {
System.out.println("+++before get name+++");
Object res = method.invoke(target, args);
System.out.println("+++after get name+++");
return res;
} else {
Object res = method.invoke(target, args);
return res;
}

}

public static void main(String[] args) {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
UserService us = new UserServiceImpl();
InvocationHandler ih = new MyInvocationHandler(us);
UserService usProxy = (UserService) Proxy.newProxyInstance(us.getClass().getClassLoader(),
us.getClass().getInterfaces(), ih);
System.out.println(usProxy.getName(1));
System.out.println(usProxy.getAge(1));
System.out.println(usProxy.getClass());
}

}


测试结果:



可以看到,对于getName方法的增强逻辑执行了。

下面我们从源码角度分析一下这个过程的实现原理,先看InvocationHandler:

InvocationHandler是一个接口,只有一个方法:

public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;


在定义增强逻辑类时,需要实现该接口,并在invoke方法里实现增强逻辑和对真实对象方法的调用。对于invoke方法的三个参数,proxy表示代理对象,method表示真实对象的方法,args表示真实对象方法的参数,这里也可以看出对真实对象方法的调用是通过反射来实现的。

增强逻辑定义好了以后,我们需要一个代理对象来执行,先看如何产生这个代理对象。代理对象的产生是通过调用Proxy类的静态方法:newProxyInstance,以下源码分析部分篇幅原因仅截取部分代码片段。

public static Object newProxyInst
4000
ance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
//该方法需要三个参数:ClassLoader确保返回的代理对象和真实对象由同一个类

加载器加载,interfaces用于定义代理类应该实现的方法,
invocationHandler用于定义代理类的增强逻辑
{
if (h == null) {
throw new NullPointerException();
}

final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}

/*
* Look up or generate the designated proxy class.
*/
//这一行代码很关键,这里是获取代理对象Class对象,Proxy类内部维护了代理
//对象的缓存,如果缓存里有则直接返回,如果没有,则生成它
Class<?> cl = getProxyClass0(loader, intfs);

/*
* Invoke its constructor with the designated invocation handler.
*/
try {
//由Class对象获取构造器
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
// create proxy instance with doPrivilege as the proxy class may
// implement non-public interfaces that requires a special permission
return AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return newInstance(cons, ih);
}
});
} else {
//最后由构造器返回新的代理对象实例
return newInstance(cons, ih);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
}
}


接下来我们看代理对象的Class对象是如何生成的,缓存逻辑略去不表,直接看没有缓存的情况,代理类Class对象由ProxyClassFactory工厂生成:

private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// prefix for all proxy class names
private static final String proxyClassNamePrefix = "$Proxy";

// next number to use for generation of unique proxy class names
private static final AtomicLong nextUniqueNumber = new AtomicLong();
//验证代码略去
/*
* Generate the specified proxy class.
*/
//这里生成了代理对象二进制字节码流
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
try {
//通过二进制字节码流加载代理类
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
}


最终生成二进制字节码流用到了Sun的ProxyGenerator类,反编译:

public static byte[] generateProxyClass(String s, Class aclass[])
{
ProxyGenerator proxygenerator = new ProxyGenerator(s, aclass);
//该方法生成代理对象的二进制字节码流
byte abyte0[] = proxygenerator.generateClassFile();
//如果要保存该字节码文件,可以将其写到硬盘上,我们稍后分析
if(saveGeneratedFiles)
//保存文件部分略去
return abyte0;
}


具体生成源码如下:

private byte[] generateClassFile() {
addProxyMethod(hashCodeMethod, java / lang / Object);
addProxyMethod(equalsMethod, java / lang / Object);
addProxyMethod(toStringMethod, java / lang / Object);
for (int i = 0; i < interfaces.length; i++) {
Method amethod[] = interfaces[i].getMethods();
for (int k = 0; k < amethod.length; k++)
addProxyMethod(amethod[k], interfaces[i]);

}

List list;
for (Iterator iterator = proxyMethods.values().iterator(); iterator.hasNext(); checkReturnTypes(list))
list = (List) iterator.next();

try {
methods.add(generateConstructor());
for (Iterator iterator1 = proxyMethods.values().iterator(); iterator1.hasNext();) {
List list1 = (List) iterator1.next();
Iterator iterator2 = list1.iterator();
while (iterator2.hasNext()) {
ProxyMethod proxymethod = (ProxyMethod) iterator2.next();
fields.add(new FieldInfo(proxymethod.methodFieldName, "Ljava/lang/reflect/Method;", 10));
methods.add(proxymethod.generateMethod());
}
}

methods.add(generateStaticInitializer());
} catch (IOException ioexception) {
throw new InternalError("unexpected I/O Exception");
}
if (methods.size() > 65535)
throw new IllegalArgumentException("method limit exceeded");
if (fields.size() > 65535)
throw new IllegalArgumentException("field limit exceeded");
cp.getClass(dotToSlash(className));
cp.getClass("java/lang/reflect/Proxy");
for (int j = 0; j < interfaces.length; j++)
cp.getClass(dotToSlash(interfaces[j].getName()));

cp.setReadOnly();
ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream();
DataOutputStream dataoutputstream = new DataOutputStream(bytearrayoutputstream);
try {
dataoutputstream.writeInt(-889275714);
dataoutputstream.writeShort(0);
dataoutputstream.writeShort(49);
cp.write(dataoutputstream);
dataoutputstream.writeShort(49);
dataoutputstream.writeShort(cp.getClass(dotToSlash(className)));
dataoutputstream.writeShort(cp.getClass("java/lang/reflect/Proxy"));
dataoutputstream.writeShort(interfaces.length);
for (int l = 0; l < interfaces.length; l++)
dataoutputstream.writeShort(cp.getClass(dotToSlash(interfaces[l].getName())));

dataoutputstream.writeShort(fields.size());
FieldInfo fieldinfo;
for (Iterator iterator3 = fields.iterator(); iterator3.hasNext(); fieldinfo.write(dataoutputstream))
fieldinfo = (FieldInfo) iterator3.next();

dataoutputstream.writeShort(methods.size());
MethodInfo methodinfo;
for (Iterator iterator4 = methods.iterator(); iterator4.hasNext(); methodinfo.write(dataoutputstream))
methodinfo = (MethodInfo) iterator4.next();

dataoutputstream.writeShort(0);
} catch (IOException ioexception1) {
throw new InternalError("unexpected I/O Exception");
}
return bytearrayoutputstream.toByteArray();
}


至此,总结一下,Proxy类通过ProxyClassFactory生成了继承Proxy类并实现了真实对象接口的 $ProxyX代理对象的二进制字节码流,并加载该字节码返回代理对象Class对象,由该Class对象经反射得到构造器构造了代理对象的实例。

在源码中我们可以通过saveGeneratedFiles变量保存生成的class文件,我们反编译上面的示例生成的class文件:

public final class $Proxy0 extends Proxy implements UserService {

private static Method m1;
private static Method m4;
private static Method m0;
private static Method m3;
private static Method m2;

public $Proxy0(InvocationHandler invocationhandler) {
super(invocationhandler);
}

public final boolean equals(Object obj) {
try {
return ((Boolean) super.h.invoke(this, m1, new Object[]{obj})).booleanValue();
} catch (Error _ex) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
//这里是UserService接口的getAge方法,在代理对象$Proxy0上的调用被invocationHandler拦截,
//经由其invoke方法调用(即我们之前定义的MyinvocationHandler的invoke方法),
//留意invoke方法的参数,我们在MyinvocationHandler里定义invoke方法时并没有使用proxy参数,
//这里proxy参数的位置传入了this变量,即代理对象本身。
public final Integer getAge(int i) {
try {
return (Integer) super.h.invoke(this, m4, new Object[]{Integer.valueOf(i)});
} catch (Error _ex) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}

public final int hashCode() {
try {
return ((Integer) super.h.invoke(this, m0, null)).intValue();
} catch (Error _ex) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}

public final String getName(int i) {
try {
return (String) super.h.invoke(this, m3, new Object[]{Integer.valueOf(i)});
} catch (Error _ex) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}

public final String toString() {
try {
return (String) super.h.invoke(this, m2, null);
} catch (Error _ex) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m4 = Class.forName("cn.john.test.dynamicProxy.UserService").getMethod("getAge", new Class[]{Integer.TYPE});
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m3 = Class.forName("cn.john.test.dynamicProxy.UserService").getMethod("getName", new Class[]{Integer.TYPE});
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
} catch (NoSuchMethodException nosuchmethodexception) {
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
} catch (ClassNotFoundException classnotfoundexception) {
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}


基于CGLIB的动态代理

使用示例

public class UserServiceB {
public String getName(int id) {
System.out.println("---getName---");
return "John";
}
public Integer getAge(int id) {
System.out.println("---getAge---");
return 10;
}
public static void main(String[] args) throws InterruptedException, IOException {
//将cglib生成的Class对象写成文件存入硬盘,后面反编译出来用以分析
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");
UserServiceB us = new UserServiceB();
// 定义增强器
Enhancer en = new Enhancer();
// 定义要代理的对象
en.setSuperclass(us.getClass());
// 定义回调函数
en.setCallback(new MethodInterceptor() {
//这里要理解intercept方法的几个参数代表的意思
//obj指的是代理类对象
//Method指的是 目标类中被拦截的方法
//args指的是 调用拦截方法所需的参数
//MethodProxy指的是用来调用目标类被拦截方法的方法,这个方法比反射更快
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy)
throws Throwable {
System.out.println("-----before-------");
//这里只能用invokeSuper,原因稍后解释
methodProxy.invokeSuper(obj, args);
System.out.println("-----after--------");
return null;
}

});
// 生成代理对象
UserServiceB usb = (UserServiceB) en.create();
// 在代理对象上调用方法
usb.getName(1);

}

}


运行结果:



同时生成了三个class文件:一个是代理类,一个是代理类的FastClass,一个是目标类的FastClass



源码分析

代理类源码概览

从上面的示例代码中,我们知道通过cglib生成代理类只需要一个目标类和一个回调函数(增强逻辑),下面我们从在代理对象上调用getName()方法出发,一步一步分析cglib动态代理的实现原理。

先来看生成的代理对象Class文件反编译后的源码(代码很长,代理了Object中的finalize,equals, toString,hashCode,clone方法,这里仅留下getName()方法):

public class UserServiceB$$EnhancerByCGLIB$$a33459ad extends UserServiceB implements Factory {
//cglib基于继承,可以看到代理类继承了目标类,并实现了Factory接口,Factory接口可以简化回调函数的变更
private boolean CGLIB$BOUND;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;//回调函数
private static final Method CGLIB$getName$0$Method;//目标类的getName方法
private static final MethodProxy CGLIB$getName$0$Proxy;//getName方法的代理方法
//初始化变量
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
//代理类
Class class_ = Class.forName("cn.john.test.dynamicProxy.UserServiceB$$EnhancerByCGLIB$$a33459ad");
//目标类
Class class_2 = Class.forName("cn.john.test.dynamicProxy.UserServiceB");
Method[] arrmethod = ReflectUtils.findMethods(
(String[]) new String[]{"getName", "(I)Ljava/lang/String;", "getAge", "(I)Ljava/lang/Integer;"},
(Method[]) class_2.getDeclaredMethods());
//getName方法
CGLIB$getName$0$Method = arrmethod[0];
//建立更快的方法索引访问方式,这里通过目标类和代理类的Class对象和方法签名为这两个对象
//的所有方法都建立了索引,并提供了通过索引调用的方法。
//这里CGLIB$getName$0$Proxy提供在目标类(或者兼容类)上快速调用getName和在代理类上
//快速调用CGLIB$getName$0的功能
CGLIB$getName$0$Proxy = MethodProxy.create(class_2, class_, (String) "(I)Ljava/lang/String;",
(String) "getName", (String) "CGLIB$getName$0");
}

//直接调用了目标类的方法,这个方法即用来执行目标类真实逻辑,通过索引调用来快速访问该方法
final String CGLIB$getName$0(int n) {
return super.getName(n);
}

//代理方法getName入口
public final String getName(int n) {
//先获取回调函数
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
UserServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$BIND_CALLBACKS((Object) this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
//获取了回调函数之后
if (methodInterceptor != null) {
//调用回调函数的拦截方法。
//注意这里传入的参数,代理类传入的this,被拦截的方法传入的是目标类对象的
//被拦截的方法,methodProxy传入的是getName方法的快速访问代理
return (String) methodInterceptor.intercept((Object) this, CGLIB$getName$0$Method,
new Object[]{new Integer(n)}, CGLIB$getName$0$Proxy);
}
return super.getName(n);
}

public UserServiceB$$EnhancerByCGLIB$$a33459ad() {
UserServiceB$$EnhancerByCGLIB$$a33459ad userServiceB$$EnhancerByCGLIB$$a33459ad = this;
UserServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$BIND_CALLBACKS((Object) userServiceB$$EnhancerByCGLIB$$a33459ad);
}

public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] arrcallback) {
CGLIB$THREAD_CALLBACKS.set(arrcallback);
}

public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] arrcallback) {
CGLIB$STATIC_CALLBACKS = arrcallback;
}

private static final void CGLIB$BIND_CALLBACKS(Object object) {
UserServiceB$$EnhancerByCGLIB$$a33459ad userServiceB$$EnhancerByCGLIB$$a33459ad = (UserServiceB$$EnhancerByCGLIB$$a33459ad) ((Object) object);
if (!userServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$BOUND) {
userServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$BOUND = true;
Object t = CGLIB$THREAD_CALLBACKS.get();
if (t != null || (v13465 = CGLIB$STATIC_CALLBACKS) != null) {
userServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$CALLBACK_0 = (MethodInterceptor) ((Callback[]) t)[0];
}
}
}
static {
UserServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$STATICHOOK1();
}
}


进入回调函数后,跟JDK动态代理InvocationHandler一样,先执行前置增强逻辑,然后将目标类的真实逻辑。注意此处目标类的真实逻辑执行cglib的实现方式与JDK实现方式不同:JDK使用的是反射技术,而cglib则使用了FastClass构建方法索引+继承的方式访问目标类的方法。

建立getName方法和CGLIB$getName0的索引

CGLIB$getName$0$Proxy = MethodProxy.create(class_2, class_, (String) "(I)Ljava/lang/String;",
(String) "getName", (String) "CGLIB$getName$0");
//注意这里class_2是目标类,class_是代理类


我们截取MethodProxy类的部分代码:

private static class CreateInfo {
Class c1;
Class c2;
NamingPolicy namingPolicy;
GeneratorStrategy strategy;
boolean attemptLoad;

public CreateInfo(Class c1, Class c2) {
this.c1 = c1;
this.c2 = c2;
AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();
if (fromEnhancer != null) {
this.namingPolicy = fromEnhancer.getNamingPolicy();
this.strategy = fromEnhancer.getStrategy();
this.attemptLoad = fromEnhancer.getAttemptLoad();
}
}
}
//注意在MethodProxy类内部变量命名:这里目标类为1,而代理类变为了2
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
//准备数据阶段,目标类和代理类的Class对象,需要映射的方法签名,这里并不会
//触发实际上的建立方法索引
MethodProxy proxy = new MethodProxy();
proxy.sig1 = new Signature(name1, desc);
proxy.sig2 = new Signature(name2, desc);
proxy.createInfo = new CreateInfo(c1, c2);
return proxy;
}


实际建立方法索引发生在回调函数中方法调用时(Lazyinit):

//MethodProxy类中的InvokeSuper
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
this.init();//实际的方法索引在此时建立
FastClassInfo fci = this.fastClassInfo;
//在代理类FastClass对象上调用索引为i2的方法
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
//内部类FastClassInfo
private static class FastClassInfo {
FastClass f1;//目标类fc
FastClass f2;//代理类fc
int i1;//目标类getName方法索引
int i2;//代理类CGLIB$getName$0方法索引

private FastClassInfo() {
}
}

private void init() {
if (this.fastClassInfo == null) {
Object object = this.initLock;
synchronized (object) {
if (this.fastClassInfo == null) {
CreateInfo ci = this.createInfo;
FastClassInfo fci = new FastClassInfo();
//这里通过字节码技术生成目标类和代理类的FastClass类的实例
//FastClass关键有两类方法:
//一类是getIndex方法,通过方法签名获取某方法的索引
//一类是invoke方法,通过方法的索引来找到方法并调用
fci.f1 = MethodProxy.helper(ci, ci.c1);//生成目标类的FastClass对象
fci.f2 = MethodProxy.helper(ci, ci.c2);//生成代理类的FastClass对象
//获取目标类和代理类的方法索引
fci.i1 = fci.f1.getIndex(this.sig1);
fci.i2 = fci.f2.getIndex(this.sig2);
this.fastClassInfo = fci;//至此,getName方法的索引建立、获取完毕
this.createInfo = null;
}
}
}
}


回到示例上层代码:
methodProxy.invokeSuper(obj, args);
这里obj是代理对象,再看invokeSuper:

public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
init();//建立和获取索引
FastClassInfo fci = fastClassInfo;
//在obj即代理对象上调用索引为i2的方法
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}


现在我们反编译代理类的FastClass类看一下,
fci.f2.invoke(fci.i2, obj, args);
到底意味着什么。

代理类FastClass(部分代码):

public class UserServiceB$$EnhancerByCGLIB$$a33459ad$$FastClassByCGLIB$$9e4fc4c5 extends FastClass {
public UserServiceB$$EnhancerByCGLIB$$a33459ad$$FastClassByCGLIB$$9e4fc4c5(Class class_) {
super(class_);
}

public int getIndex(Signature signature) {
String string = signature.toString();
switch (string.hashCode()) {
case -2024387448 : {
//在上面的Init方法中我们已经获取了CGLIB$getName$0的索引,值为18
if (!string.equals("CGLIB$getName$0(I)Ljava/lang/String;"))
break;
return 18;
}
case 206620625 : {
if (!string.equals("getName(I)Ljava/lang/String;"))
break;
return 3;
}
}
return -1;
}
//在代理对象上调用索引为18的方法
public Object invoke(int n, Object object, Object[] arrobject) throws InvocationTargetException {
UserServiceB$$EnhancerByCGLIB$$a33459ad userServiceB$$EnhancerByCGLIB$$a33459ad = (UserServiceB$$EnhancerByCGLIB$$a33459ad) ((Object) object);
try {
switch (n) {
case 3 : {
return userServiceB$$EnhancerByCGLIB$$a33459ad.getName(((Number) arrobject[0]).intValue());
}
//在代理对象上调用了CGLIB$getName$0方法,回到代理类源码,它调用super.getName,即目标类的真实逻辑
case 18 : {
return userServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$getName$0(((Number) arrobject[0]).intValue());
}
}
} catch (Throwable v1) {
throw new InvocationTargetException(v1);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
}


现在我们来回答一下为什么示例代码中不能调用invoke,而是只能调用invokeSuper。invoke代码:

public Object invoke(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
//因为在回调函数中obj传入的代理对象,这里实际上是在代理对象上调用
//getName方法,将陷入无限递归,直至栈溢出
return fci.f1.invoke(fci.i1, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (IllegalArgumentException e) {
if (fastClassInfo.i1 < 0)
throw new IllegalArgumentException("Protected method: " + sig1);
throw e;
}
}


总结

类型机制回调方式适用场景效率
JDK动态代理委托机制,代理类和目标类都实现了同样的接口,InvocationHandler持有目标类,代理类委托InvocationHandler去调用目标类的原始方法反射目标类是接口类效率瓶颈在反射调用稍慢
CGLIB动态代理继承机制,代理类继承了目标类并重写了目标方法,通过回调函数MethodInterceptor调用父类方法执行原始逻辑通过FastClass方法索引调用非接口类,非final类,非final方法第一次调用因为要生成多个Class对象较JDK方式慢,多次调用因为有方法索引较反射方式快,如果方法过多switch case过多其效率还需测试
http://ifeve.com/jdk%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E4%BB%A3%E7%90%86%E4%B8%8Ecglib%E4%BB%A3%E7%90%86%E5%8E%9F%E7%90%86%E6%8E%A2%E7%A9%B6/

https://www.jianshu.com/p/9a61af393e41?from=timeline&isappinstalled=0

https://www.jianshu.com/p/13aa63e1ac95

https://www.cnblogs.com/cruze/p/3865180.html

spring技术内幕
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息