目录
3.1.使用CGLIB代理执行非接口实现类HelloWorld
3.2.使用CGLIB代理执行接口实现类UserServiceImpl
3.3.使用JDK动态代理执行接口实现类UserServiceImpl
3.1.使用JDK动态代理执行非接口实现类HelloWorld
2.3类MethodProxy中invoke和invokeSuper执行源码分析及区别
JDK动态代理和CGLIB代理算是java的基础知识点,在面试场合经常被问到,他们的使用方式、原理及区别是怎样的呢,下面我们一起来解读下。
以下本次研究的涉及到的版本:
jdk1.8
cglib3.3.0
cglib是一个强大的、高性能、高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口,cglib封装了asm,可以在运行期动态生成新的 class,Hibernate和Spring都用到过它。cglib用于AOP,jdk中的proxy必须基于接口,cglib却没有这个限制。
ASM是一个Java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能。ASM可以直接产生二进制class文件,也可以在类被加载入Java虚拟机之前动态改变类行为。Java class被存储在严格格式定义的.class文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。
一、使用方式
需注意,正常我们谈jdk动态代理和cglib代理时,使用比较多的场景是在spring的aop里,但在spring的aop中最终实现的仍是jdk和cglib提供的基础方法,所以我们还是先从基础方法说起,那么在spring中就更容易理解了。
1.业务方法类
首先,创建一个没有实现接口的类HelloWorld,
package com.test.proxy;
public class HelloWorld {
public void sayHello(){
System.out.println("say HelloWorld");
}
}
创建一个接口
package com.test.proxy;
public interface UserService {
void addUser();
}
创建一个实现类
package com.test.proxy;
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("register algo");
}
}
2.实现代理方法
实现JDK动态代理方法,
package com.test.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxy implements InvocationHandler {
// 需要代理的目标对象
private Object targetObject;
/**
* 创建代理对象
* @param targetObject
* @return
*/
public Object createProxy(Object targetObject) {
this.targetObject = targetObject;
// 返回代理对象
Object proxyObj = Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
return proxyObj;
}
/**
* invoke方法
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 检查权限
checkPopedom();
Object ret = null;
try {
// 前置通知
before();
// 调用invoke方法
ret = method.invoke(targetObject, args);
// 后置通知
after();
} catch (Exception e) {
// 异常通知
exception();
} finally {
// 方法返回前通知
beforeReturning();
}
return ret;
}
private void before() {
System.out.println("JDKProxy:before method invoke...");
}
private void after() {
System.out.println("JDKProxy:after method invoke...");
}
private void exception() {
System.out.println("JDKProxy:exception method invoke...");
}
private void beforeReturning() {
System.out.println("JDKProxy:beforeReturning method invoke...");
}
private void checkPopedom() {// 模拟检查权限的例子
System.out.println("JDKProxy:检查权限 checkPopedom()!");
}
}
实现CGLIB代理方法,
package com.test.proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGLibProxy implements MethodInterceptor {
// CGLib需要代理的目标对象
private Object targetObject;
/**
* 创建代理对象
* @param obj
* @return
*/
public Object createProxy(Object obj) {
this.targetObject = obj;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
enhancer.setCallback(this);
Object proxyObj = enhancer.create();
return proxyObj;
}
/**
* intercept方法
* @param proxy
* @param method
* @param args
* @param methodProxy
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 检查权限
checkPopedom();
Object obj = null;
try {
// 前置通知
before();
// 调用invoke方法
obj = method.invoke(targetObject, args);
// 后置通知
after();
} catch (Exception e) {
// 异常通知
exception();
} finally {
// 方法返回前通知
beforeReturning();
}
return obj;
}
private void before() {
System.out.println("CGLibProxy:before method invoke...");
}
private void after() {
System.out.println("CGLibProxy:after method invoke...");
}
private void exception() {
System.out.println("CGLibProxy:exception method invoke...");
}
private void beforeReturning() {
System.out.println("CGLibProxy:beforeReturning method invoke...");
}
private void checkPopedom() {
System.out.println("CGLibProxy:检查权限 checkPopedom()!");
}
}
由上可以看出,
JDK动态代理方法,需要实现InvocationHandler接口,并重写invoke方法(可以在invoke()方法进行面向切面的处理,调用相应通知),而创建代理对象是通过Proxy类的newProxyInstance方法实现的,invoke方法的作用是,调用的时候,执行切面逻辑,以及通过Method的invoke的反射机制调用目标类的原始方法。
CGLIB代理方法,需要实现MethodInterceptor接口,并重写intercept方法(可以在intercept()方法进行面向切面的处理,调用相应通知),而创建代理对象是通过Enhancer类实现的,intercept方法的作用是,调用的时候,执行切面逻辑,以及通过Method的invoke的反射机制调用目标类的原始方法,或者用MethodProxy.invokeSuper方法,通过fastclass机制直接调用目标类的原始方法。
3.使用场景分析
其实,两个代理方法都可以完成代理的工作,那么结合具体场景分析下区别,
3.1.使用CGLIB代理执行非接口实现类HelloWorld
package com.test.proxy;
import net.sf.cglib.core.DebuggingClassWriter;
public class ProxyPerformanceTest {
public static void main(String[] args) {
// 该方法是为了生成由CGLIB生成的代理对象CLASS文件
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");
System.out.println("-----------CGLibProxy not use interface start-------------");
HelloWorld helloWorldCglib = (HelloWorld) new CGLibProxy().createProxy(new HelloWorld());
helloWorldCglib.sayHello();
System.out.println("-----------CGLibProxy not use interface end-------------");
}
}
执行结果为,
-----------CGLibProxy not use interface start-------------
CGLIB debugging enabled, writing to 'D:\class'
CGLibProxy:检查权限 checkPopedom()!
CGLibProxy:before method invoke...
say HelloWorld
CGLibProxy:after method invoke...
CGLibProxy:beforeReturning method invoke...
-----------CGLibProxy not use interface end-------------
生成的代理class文件内容,
package com.test.proxy;
import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
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 HelloWorld$$EnhancerByCGLIB$$74b9b49 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$equals$1$Method;
private static final MethodProxy CGLIB$equals$1$Proxy;
private static final Method CGLIB$toString$2$Method;
private static final MethodProxy CGLIB$toString$2$Proxy;
private static final Method CGLIB$hashCode$3$Method;
private static final MethodProxy CGLIB$hashCode$3$Proxy;
private static final Method CGLIB$clone$4$Method;
private static final MethodProxy CGLIB$clone$4$Proxy;
static void CGLIB$STATICHOOK2() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("com.test.proxy.HelloWorld$$EnhancerByCGLIB$$74b9b49");
Class var1;
CGLIB$sayHello$0$Method = ReflectUtils.findMethods(new String[]{"sayHello", "()V"}, (var1 = Class.forName("com.test.proxy.HelloWorld")).getDeclaredMethods())[0];
CGLIB$sayHello$0$Proxy = MethodProxy.create(var1, var0, "()V", "sayHello", "CGLIB$sayHello$0");
Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$equals$1$Method = var10000[0];
CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
CGLIB$toString$2$Method = var10000[1];
CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
CGLIB$hashCode$3$Method = var10000[2];
CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
CGLIB$clone$4$Method = var10000[3];
CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
}
final void CGLIB$sayHello$0() {
super.sayHello();
}
public final void sayHello() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
} else {
super.sayHello();
}
}
final boolean CGLIB$equals$1(Object var1) {
return super.equals(var1);
}
public final boolean equals(Object var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
return var2 == null ? false : (Boolean)var2;
} else {
return super.equals(var1);
}
}
final String CGLIB$toString$2() {
return super.toString();
}
public final String toString() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
}
final int CGLIB$hashCode$3() {
return super.hashCode();
}
public final int hashCode() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
return var1 == null ? 0 : ((Number)var1).intValue();
} else {
return super.hashCode();
}
}
final Object CGLIB$clone$4() throws CloneNotSupportedException {
return super.clone();
}
protected final Object clone() throws CloneNotSupportedException {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
}
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return CGLIB$clone$4$Proxy;
}
break;
case 1535311470:
if (var10000.equals("sayHello()V")) {
return CGLIB$sayHello$0$Proxy;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return CGLIB$equals$1$Proxy;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return CGLIB$toString$2$Proxy;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return CGLIB$hashCode$3$Proxy;
}
}
return null;
}
public HelloWorld$$EnhancerByCGLIB$$74b9b49() {
CGLIB$BIND_CALLBACKS(this);
}
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
CGLIB$THREAD_CALLBACKS.set(var0);
}
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
CGLIB$STATIC_CALLBACKS = var0;
}
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
HelloWorld$$EnhancerByCGLIB$$74b9b49 var1 = (HelloWorld$$EnhancerByCGLIB$$74b9b49)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if (var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if (var10000 == null) {
return;
}
}
var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
}
}
public Object newInstance(Callback[] var1) {
CGLIB$SET_THREAD_CALLBACKS(var1);
HelloWorld$$EnhancerByCGLIB$$74b9b49 var10000 = new HelloWorld$$EnhancerByCGLIB$$74b9b49();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Callback var1) {
CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
HelloWorld$$EnhancerByCGLIB$$74b9b49 var10000 = new HelloWorld$$EnhancerByCGLIB$$74b9b49();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
HelloWorld$$EnhancerByCGLIB$$74b9b49 var10000 = new HelloWorld$$EnhancerByCGLIB$$74b9b49;
switch(var1.length) {
case 0:
var10000.<init>();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
default:
throw new IllegalArgumentException("Constructor not found");
}
}
public Callback getCallback(int var1) {
CGLIB$BIND_CALLBACKS(this);
MethodInterceptor var10000;
switch(var1) {
case 0:
var10000 = this.CGLIB$CALLBACK_0;
break;
default:
var10000 = null;
}
return var10000;
}
public void setCallback(int var1, Callback var2) {
switch(var1) {
case 0:
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
default:
}
}
public Callback[] getCallbacks() {
CGLIB$BIND_CALLBACKS(this);
return new Callback[]{this.CGLIB$CALLBACK_0};
}
public void setCallbacks(Callback[] var1) {
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
}
static {
CGLIB$STATICHOOK2();
}
}
由上可以看出,生成的代理对象是目标对象HelloWorld的子类,且实现了目标对象的sayHello方法,这里也间接说明了CGLIB不能代理final修饰的类或者方法。
3.2.使用CGLIB代理执行接口实现类UserServiceImpl
package com.test.proxy;
import net.sf.cglib.core.DebuggingClassWriter;
public class ProxyPerformanceTest {
public static void main(String[] args) {
// 该方法是为了生成由CGLIB生成的代理对象CLASS文件
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");
System.out.println("-----------CGLibProxy use interface start-------------");
UserService userServiceCglib = (UserService) new CGLibProxy().createProxy(new UserServiceImpl());
userServiceCglib.addUser();
System.out.println("-----------CGLibProxy use interface end-------------");
}
}
执行结果为,
-----------CGLibProxy use interface start-------------
CGLIB debugging enabled, writing to 'D:\class'
CGLibProxy:检查权限 checkPopedom()!
CGLibProxy:before method invoke...
register algo
CGLibProxy:after method invoke...
CGLibProxy:beforeReturning method invoke...
-----------CGLibProxy use interface end-------------
生成的代理class文件内容如下,
package com.test.proxy;
import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
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 UserServiceImpl$$EnhancerByCGLIB$$519ec1cd extends UserServiceImpl 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$addUser$0$Method;
private static final MethodProxy CGLIB$addUser$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$equals$1$Method;
private static final MethodProxy CGLIB$equals$1$Proxy;
private static final Method CGLIB$toString$2$Method;
private static final MethodProxy CGLIB$toString$2$Proxy;
private static final Method CGLIB$hashCode$3$Method;
private static final MethodProxy CGLIB$hashCode$3$Proxy;
private static final Method CGLIB$clone$4$Method;
private static final MethodProxy CGLIB$clone$4$Proxy;
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("com.test.proxy.UserServiceImpl$$EnhancerByCGLIB$$519ec1cd");
Class var1;
Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$equals$1$Method = var10000[0];
CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
CGLIB$toString$2$Method = var10000[1];
CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
CGLIB$hashCode$3$Method = var10000[2];
CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
CGLIB$clone$4$Method = var10000[3];
CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
CGLIB$addUser$0$Method = ReflectUtils.findMethods(new String[]{"addUser", "()V"}, (var1 = Class.forName("com.test.proxy.UserServiceImpl")).getDeclaredMethods())[0];
CGLIB$addUser$0$Proxy = MethodProxy.create(var1, var0, "()V", "addUser", "CGLIB$addUser$0");
}
final void CGLIB$addUser$0() {
super.addUser();
}
public final void addUser() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$addUser$0$Method, CGLIB$emptyArgs, CGLIB$addUser$0$Proxy);
} else {
super.addUser();
}
}
final boolean CGLIB$equals$1(Object var1) {
return super.equals(var1);
}
public final boolean equals(Object var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
return var2 == null ? false : (Boolean)var2;
} else {
return super.equals(var1);
}
}
final String CGLIB$toString$2() {
return super.toString();
}
public final String toString() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
}
final int CGLIB$hashCode$3() {
return super.hashCode();
}
public final int hashCode() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
return var1 == null ? 0 : ((Number)var1).intValue();
} else {
return super.hashCode();
}
}
final Object CGLIB$clone$4() throws CloneNotSupportedException {
return super.clone();
}
protected final Object clone() throws CloneNotSupportedException {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
}
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return CGLIB$clone$4$Proxy;
}
break;
case 1761046505:
if (var10000.equals("addUser()V")) {
return CGLIB$addUser$0$Proxy;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return CGLIB$equals$1$Proxy;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return CGLIB$toString$2$Proxy;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return CGLIB$hashCode$3$Proxy;
}
}
return null;
}
public UserServiceImpl$$EnhancerByCGLIB$$519ec1cd() {
CGLIB$BIND_CALLBACKS(this);
}
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
CGLIB$THREAD_CALLBACKS.set(var0);
}
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
CGLIB$STATIC_CALLBACKS = var0;
}
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
UserServiceImpl$$EnhancerByCGLIB$$519ec1cd var1 = (UserServiceImpl$$EnhancerByCGLIB$$519ec1cd)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if (var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if (var10000 == null) {
return;
}
}
var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
}
}
public Object newInstance(Callback[] var1) {
CGLIB$SET_THREAD_CALLBACKS(var1);
UserServiceImpl$$EnhancerByCGLIB$$519ec1cd var10000 = new UserServiceImpl$$EnhancerByCGLIB$$519ec1cd();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Callback var1) {
CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
UserServiceImpl$$EnhancerByCGLIB$$519ec1cd var10000 = new UserServiceImpl$$EnhancerByCGLIB$$519ec1cd();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
UserServiceImpl$$EnhancerByCGLIB$$519ec1cd var10000 = new UserServiceImpl$$EnhancerByCGLIB$$519ec1cd;
switch(var1.length) {
case 0:
var10000.<init>();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
default:
throw new IllegalArgumentException("Constructor not found");
}
}
public Callback getCallback(int var1) {
CGLIB$BIND_CALLBACKS(this);
MethodInterceptor var10000;
switch(var1) {
case 0:
var10000 = this.CGLIB$CALLBACK_0;
break;
default:
var10000 = null;
}
return var10000;
}
public void setCallback(int var1, Callback var2) {
switch(var1) {
case 0:
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
default:
}
}
public Callback[] getCallbacks() {
CGLIB$BIND_CALLBACKS(this);
return new Callback[]{this.CGLIB$CALLBACK_0};
}
public void setCallbacks(Callback[] var1) {
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
}
static {
CGLIB$STATICHOOK1();
}
}
由上可以看出,生成的代理对象是目标对象UserServiceImpl的子类,且实现了目标对象的addUser方法。
3.3.使用JDK动态代理执行接口实现类UserServiceImpl
package com.test.proxy;
import net.sf.cglib.core.DebuggingClassWriter;
public class ProxyPerformanceTest {
public static void main(String[] args) {
// 该方法是为了生成由JDK代理生成的代理对象CLASS文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
System.out.println("-----------JDKProxy use interface start-------------");
UserService userServiceJdk = (UserService) new JDKProxy().createProxy(new UserServiceImpl());
userServiceJdk.addUser();
System.out.println("-----------JDKProxy use interface end-------------");
}
}
执行结果如下,
-----------JDKProxy use interface start-------------
JDKProxy:检查权限 checkPopedom()!
JDKProxy:before method invoke...
register algo
JDKProxy:after method invoke...
JDKProxy:beforeReturning method invoke...
-----------JDKProxy use interface end-------------
生成的代理class文件内容如下,
package com.sun.proxy;
import com.test.proxy.UserService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements UserService {
private static Method m1;
private static Method m2;
private static Method m0;
private static Method m3;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void addUser() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m3 = Class.forName("com.test.proxy.UserService").getMethod("addUser");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
由上可以看出,生成的代理类继承Proxy(默认),但是实现了UserService接口,并且重写了addUser方法。这里需要补充的一点是,因为jdk动态代理方法默认让代理对象继承Proxy,而java里是不支持多继承的,所以如果要通过jdk动态代理实现代理,那么目标对象必须实现接口才能被代理,我们可以通过3.4场景进行验证。
在重写的addUser方法里,通过super.h.invoke调用代理类JDKProxy中的invoke方法来完成的。
3.1.使用JDK动态代理执行非接口实现类HelloWorld
package com.test.proxy;
import net.sf.cglib.core.DebuggingClassWriter;
public class ProxyPerformanceTest {
public static void main(String[] args) {
// 该方法是为了生成由JDK代理生成的代理对象CLASS文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
System.out.println("-----------JDKProxy not use interface start-------------");
HelloWorld helloWorldJdk = (HelloWorld) new JDKProxy().createProxy(new HelloWorld());
helloWorldJdk.sayHello();
System.out.println("-----------JDKProxy not use interface end-------------");
}
}
执行结果如下,
-----------JDKProxy not use interface start-------------
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to com.test.proxy.HelloWorld
at com.test.proxy.ProxyPerformanceTest.main(ProxyPerformanceTest.java:12)
如上,创建代理对象是成功的,只是在强制把代理对象转换为HelloWorld的时候失败了,我们来看下实际生成的代理对象。如下,
package com.sun.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy1 extends Proxy {
private static Method m1;
private static Method m2;
private static Method m0;
public $Proxy1(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
很清晰了,因为HelloWorld不是接口实现类,所以生成的代理对象没有实现或者继承HelloWorld,故转换成HelloWorld时,肯定是失败的。
二、源码分析
1.JDK动态代理源码分析
1.1创建代理对象
JDK动态代理创建代理对象通过Proxy.newProxyInstance方法完成,首先看下这个方法几个参数的意思。
loader:一个classloader对象,定义了由哪个classloader对象对生成的代理类进行加载。
interfaces: 一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口,如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法。
h: 一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用,会调用h里面的invoke方法去执行。
newProxyInstance源码如下,
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
// 校验InvocationHandler不能为空
Objects.requireNonNull(h);
// 克隆该类实现的所有接口
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
// 进行权限校验,非关键代码可以不用关心
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
// 这个是关键代码,根据classloader、interfaces生成代理类字节码,直接生成的.class不是生成.java编译的
Class<?> cl = getProxyClass0(loader, intfs);
// 使用自定义的InvocationHandler作为参数,调用构造函数获取代理类对象实例
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
// 获取代理类的构造函数,入参为InvocationHandler
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
// 判断代理类是否是Public的,不是public的则取消构造器验证权限限制
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
// 设置在使用构造器的时候不执行权限检查
cons.setAccessible(true);
return null;
}
});
}
// 通过构造函数实例化代理类,这里为什么用newInstance可以查下new和newInstance的区别,还有这里实例化的时候把h带进去了,
// h是InvocationHandler,可以看jdk动态代理生成的代理类中构造函数是什么样的就知道为什么传h了
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
可以看出,生成代理对象分为以下三步:
第一步,通过classLoader,interfaces创建代理对象;
第二步,通过代理类Class获取入参为{InvocationHandler}的构造器;
第三步,通过构造器实例化代理对象。
其中,第一步最关键,getProxyClass0源码如下,
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
// 接口数量不能超过65535
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
// 判断给定的代理类是否在缓存中存在,如果存在则直接返回副本,否则通过ProxyClassFactory创建
return proxyClassCache.get(loader, interfaces);
}
这里我们重点关注代理类是如何生成的,缓存的机制先略过(不是本文重点),proxyClassCache.get里生成代理调用的是ProxyClassFactory的apply方法,源码如下,
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// 代理类的前缀,所以为什么jdk动态代理生成的类都是$Proxy开头的
private static final String proxyClassNamePrefix = "$Proxy";
// 生成一个数字,保证唯一性,用于代理类的名称
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
// 遍历接口
for (Class<?> intf : interfaces) {
// 校验类加载器是否能通过接口名称加载该类,这个加载器是被代理目标类的加载器
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
// 校验是否是接口
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
// 校验接口是否重复
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
String proxyPkg = null; // 定义代理类的包
int accessFlags = Modifier.PUBLIC | Modifier.FINAL; // 访问标志
// 非public接口,代理类的包名与接口的包名相同
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// public代理接口,使用com.sun.proxy包名
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
// 为代理类生成名字
// 如:com.sun.proxy.$Proxy0
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
// 生成代理对象的字节码,即class文件
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
// 使用类加载器将代理类的字节码文件加载到JVM中,native方法,然后返回代理类class对象
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}
}
生成代理对象字节码的方法generateProxyClass,源码如下,
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
// 生成代理类的字节码
final byte[] var4 = var3.generateClassFile();
// 是否要将生成代理类的字节码文件保存到磁盘中,该变量可以通过系统属性设置
if (saveGeneratedFiles) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
try {
int var1 = var0.lastIndexOf(46);
Path var2;
if (var1 > 0) {
Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
Files.createDirectories(var3);
var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
} else {
var2 = Paths.get(var0 + ".class");
}
// 将文件写入磁盘
Files.write(var2, var4, new OpenOption[0]);
return null;
} catch (IOException var4x) {
throw new InternalError("I/O exception saving generated file: " + var4x);
}
}
});
}
return var4;
}
以上就是jdk动态代理创建代理类文件的过程。
1.2调用代理对象
从第一部分的3.3示例中生成的代理类,可以看出,代理类中重写的业务里的addUser方法,实际执行该方法时,通过super.h.invoke调用代理类JDKProxy中的invoke方法来完成的,该invoke方法时通过反射机制调用目标类的原始方法。
2.CGLIB代理源码分析
2.1创建代理对象
由第一步的3.1场景,创建代理对象执行的是enhancer.create()方法,看下执行的源码,如下,
public Object create() {
this.classOnly = false;
this.argumentTypes = null;
return this.createHelper();
}
private Object createHelper() {
// 校验callbackTypes、filter是否为空,以及为空时的处理
this.preValidate();
// 通过newInstance方法来创建EnhancerKey对象
Object key = KEY_FACTORY.newInstance(this.superclass != null ? this.superclass.getName() : null, ReflectUtils.getNames(this.interfaces), this.filter == ALL_ZERO ? null : new WeakCacheKey(this.filter), this.callbackTypes, this.useFactory, this.interceptDuringConstruction, this.serialVersionUID);
// 设置当前enhancer的代理类的key标识
this.currentKey = key;
// 调用父类即AbstractClassGenerator的创建代理类
Object result = super.create(key);
return result;
}
然后执行的AbstractClassGenerator.java中的create方法,源码如下,
protected Object create(Object key) {
try {
// 获取到当前生成器的类加载器
ClassLoader loader = this.getClassLoader();
// 当前类加载器对应的缓存,缓存key为类加载器,缓存的value为ClassLoaderData
Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> cache = CACHE;
// 先从缓存中获取下当前类加载器所有加载过的类
AbstractClassGenerator.ClassLoaderData data = (AbstractClassGenerator.ClassLoaderData)cache.get(loader);
// 如果为空
if (data == null) {
Class var5 = AbstractClassGenerator.class;
synchronized(AbstractClassGenerator.class) {
cache = CACHE;
data = (AbstractClassGenerator.ClassLoaderData)cache.get(loader);
// 经典的防止并发修改 二次判断
if (data == null) {
// 新建一个缓存Cache 并将之前的缓存Cache的数据添加进来 并将已经被gc回收的数据给清除掉
Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> newCache = new WeakHashMap(cache);
// 新建一个当前加载器对应的ClassLoaderData 并加到缓存中 但ClassLoaderData中此时还没有数据
data = new AbstractClassGenerator.ClassLoaderData(loader);
newCache.put(loader, data);
// 刷新全局缓存
CACHE = newCache;
}
}
}
// 设置一个全局key
this.key = key;
// 在刚创建的data(ClassLoaderData)中调用get方法 并将当前生成器,
// 以及是否使用缓存的标识传进去,系统参数 System.getProperty("cglib.useCache", "true")
// 返回的是生成好的代理类的class信息
Object obj = data.get(this, this.getUseCache());
// 如果为class则实例化class并返回,就是我们需要的代理类对象
// 如果不是则说明是实体 则直接执行另一个方法返回实体对象
return obj instanceof Class ? this.firstInstance((Class)obj) : this.nextInstance(obj);
} catch (RuntimeException var9) {
throw var9;
} catch (Error var10) {
throw var10;
} catch (Exception var11) {
throw new CodeGenerationException(var11);
}
}
这个方法可以看到主要为根据类加载器定义一个缓存,里面装载了缓存的类信息,然后调用这个ClassLoaderData的get方法获取到数据,如果为class信息 那么直接使用反射实例化,如果返回的是实体类,则解析实体类的信息,调用其newInstance方法重新生成一个实例(cglib的代理类都会生成newInstance方法)。
重点看下data.get(this, this.getUseCache())方法实现,
public Object get(AbstractClassGenerator gen, boolean useCache) {
// 如果不用缓存 (默认使用)
if (!useCache) {
// 则直接调用生成器的命令
return gen.generate(this);
} else {
// 从缓存中获取值
Object cachedValue = this.generatedClasses.get(gen);
// 解包装并返回
return gen.unwrapCachedValue(cachedValue);
}
}
我们重点看如何生成代理类,gen.generate方法最终调用AbstractClassGenerator的generate方法,如下,
protected Class generate(ClassLoaderData data) {
this.validate();
if (this.superclass != null) {
this.setNamePrefix(this.superclass.getName());
} else if (this.interfaces != null) {
this.setNamePrefix(this.interfaces[ReflectUtils.findPackageProtected(this.interfaces)].getName());
}
return super.generate(data);
}
protected Class generate(AbstractClassGenerator.ClassLoaderData data) {
Object save = CURRENT.get();
// 当前的代理类生成器存入ThreadLocal中
CURRENT.set(this);
try {
// 获取到ClassLoader
ClassLoader classLoader = data.getClassLoader();
// 判断不能为空
if (classLoader == null) {
throw new IllegalStateException("ClassLoader is null while trying to define class " + this.getClassName() + ". It seems that the loader has been expired from a weak reference somehow. Please file an issue at cglib's issue tracker.");
} else {
String className;
synchronized(classLoader) {
// 生成代理类名字
className = this.generateClassName(data.getUniqueNamePredicate());
// 缓存中存入这个名字
data.reserveName(className);
// 当前代理类生成器设置类名
this.setClassName(className);
}
Class gen;
// 尝试从缓存中获取类
if (this.attemptLoad) {
try {
// 要是能获取到就直接返回了,即可能出现并发 其他线程已经加载
gen = classLoader.loadClass(this.getClassName());
Class var25 = gen;
return var25;
} catch (ClassNotFoundException var20) {
}
}
// 生成字节码
byte[] b = this.strategy.generate(this);
// 获取到字节码代表的class的名字
className = ClassNameReader.getClassName(new ClassReader(b));
// 核实是否为protect
ProtectionDomain protectionDomain = this.getProtectionDomain();
synchronized(classLoader) {
// 如果不是protect
if (protectionDomain == null) {
// 根据字节码、类加载器以及类名字,将class加载到内存中
gen = ReflectUtils.defineClass(className, b, classLoader);
} else {
// 根据字节码、类加载器以及类名字,以及找到的Protect级别的实体,将class加载到内存中
gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain);
}
}
// 返回生成的class信息
Class var8 = gen;
return var8;
}
} catch (RuntimeException var21) {
throw var21;
} catch (Error var22) {
throw var22;
} catch (Exception var23) {
throw new CodeGenerationException(var23);
} finally {
CURRENT.set(save);
}
}
这个方法主要设置了下当前类生成器的类名,然后调用stratege的generate方法返回字节码,根据字节码 类名 类加载器将字节码所代表的类加载到内存中,这个功能看一下大概就懂,我们接下来主要分析字节码生成方法。
public byte[] generate(ClassGenerator cg) throws Exception {
// 创建一个写入器
DebuggingClassWriter cw = this.getClassVisitor();
// 加入自己的转换逻辑后执行代理类生成器的generateClass方法
this.transform(cg).generateClass(cw);
// 将cw写入的东西转换为byte数组返回
return this.transform(cw.toByteArray());
}
上面的generateClass调用的是Enhancer的generateClass方法,源码如下,
public void generateClass(ClassVisitor v) throws Exception {
// 声明需代理的类 或者接口
Class sc = this.superclass == null ? Object.class : this.superclass;
// 检查 final类无法被继承
if (TypeUtils.isFinal(sc.getModifiers())) {
throw new IllegalArgumentException("Cannot subclass final class " + sc.getName());
} else {
// 找到该类所有声明了的构造函数
List constructors = new ArrayList(Arrays.asList(sc.getDeclaredConstructors()));
// 去掉private之类的不能被继承的构造函数
this.filterConstructors(sc, constructors);
// Order is very important: must add superclass, then
// its superclass chain, then each interface and
// its superinterfaces.
// 这儿顺序非常重要 上面是源码的注释 直接留着 相信大家都能看懂
// 声明代理类方法集合
List actualMethods = new ArrayList();
// 声明代理接口接口方法集合
List interfaceMethods = new ArrayList();
// 声明所有必须为public的方法集合,这儿主要是代理接口接口的方法
final Set forcePublic = new HashSet();
// 即通过传入的代理类,代理接口,遍历所有的方法并放入对应的集合
getMethods(sc, this.interfaces, actualMethods, interfaceMethods, forcePublic);
// 对所有代理类方法修饰符做处理
List methods = CollectionUtils.transform(actualMethods, new Transformer() {
public Object transform(Object value) {
Method method = (Method)value;
int modifiers = 16 | method.getModifiers() & -1025 & -257 & -33;
if (forcePublic.contains(MethodWrapper.create(method))) {
modifiers = modifiers & -5 | 1;
}
return ReflectUtils.getMethodInfo(method, modifiers);
}
});
// 创建类写入器
ClassEmitter e = new ClassEmitter(v);
// 1.开始创建类 并写入基本信息 如java版本,类修饰符 类名等
if (this.currentData == null) {
e.begin_class(52, 1, this.getClassName(), Type.getType(sc), this.useFactory ? TypeUtils.add(TypeUtils.getTypes(this.interfaces), FACTORY) : TypeUtils.getTypes(this.interfaces), "<generated>");
} else {
e.begin_class(52, 1, this.getClassName(), (Type)null, new Type[]{FACTORY}, "<generated>");
}
List constructorInfo = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance());
// 2. 声明一个private boolean 类型的属性:CGLIB$BOUND
e.declare_field(2, "CGLIB$BOUND", Type.BOOLEAN_TYPE, (Object)null);
// 3. 声明一个public static Object 类型的属性:CGLIB$FACTORY_DATA
e.declare_field(9, "CGLIB$FACTORY_DATA", OBJECT_TYPE, (Object)null);
// 这个默认为true 如果为false则会声明一个private boolean 类型的属性:CGLIB$CONSTRUCTED
if (!this.interceptDuringConstruction) {
e.declare_field(2, "CGLIB$CONSTRUCTED", Type.BOOLEAN_TYPE, (Object)null);
}
// 4. 声明一个public static final 的ThreadLocal:ThreadLocal
e.declare_field(26, "CGLIB$THREAD_CALLBACKS", THREAD_LOCAL, (Object)null);
// 5. 声明一个public static final 的CallBack类型的数组:CGLIB$STATIC_CALLBACKS
e.declare_field(26, "CGLIB$STATIC_CALLBACKS", CALLBACK_ARRAY, (Object)null);
// 如果serialVersionUID不为null 则设置一个public static final 的Long类型 serialVersionUID
if (this.serialVersionUID != null) {
e.declare_field(26, "serialVersionUID", Type.LONG_TYPE, this.serialVersionUID);
}
// 遍历CallBackTypes 即我们构建Enhancer是setCallBack的所有类的类型 本案例中是methodInterceptor 并且只传入了一个
for(int i = 0; i < this.callbackTypes.length; ++i) {
// 6.声明一个private 的传入的CallBack类型的属性:CGLIB$CALLBACK_0 (从0开始编号,)
e.declare_field(2, getCallbackField(i), this.callbackTypes[i], (Object)null);
}
// 7声明一个private static 的传入的Object类型的属性:CGLIB$CALLBACK_FILTER
e.declare_field(10, "CGLIB$CALLBACK_FILTER", OBJECT_TYPE, (Object)null);
// 判断currentData
if (this.currentData == null) {
// 8.为null则开始声明所有的代理类方法的变量 以及其具体的重写实现方法,还有static初始化执行代码块
this.emitMethods(e, methods, actualMethods);
// 9.声明构造函数
this.emitConstructors(e, constructorInfo);
} else {
// 声明默认构造函数
this.emitDefaultConstructor(e);
}
this.emitSetThreadCallbacks(e);
this.emitSetStaticCallbacks(e);
this.emitBindCallbacks(e);
// 如果currentData不为null
if (this.useFactory || this.currentData != null) {
// 获取到所有CallBack索引数组
int[] keys = this.getCallbackKeys();
// 10.声明三个newInstance方法
// 只有一个callback参数
this.emitNewInstanceCallbacks(e);
// 参数为callback数组
this.emitNewInstanceCallback(e);
// 参数为callback数组 以及附带的一些参数
this.emitNewInstanceMultiarg(e, constructorInfo);
// 11.声明getCallBack方法
this.emitGetCallback(e, keys);
// 12.声明setCallBack方法
this.emitSetCallback(e, keys);
// 13.声明getCallBack方法
this.emitGetCallbacks(e);
// 14.声明setCallBacks方法
this.emitSetCallbacks(e);
}
// 类声明结束
e.end_class();
}
}
DebuggingClassWriter中toByteArray方法源码如下,
public byte[] toByteArray() {
return (byte[])((byte[])AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
byte[] b = ((ClassWriter)DebuggingClassWriter.access$001(DebuggingClassWriter.this)).toByteArray();
if (DebuggingClassWriter.debugLocation != null) {
String dirs = DebuggingClassWriter.this.className.replace('.', File.separatorChar);
try {
(new File(DebuggingClassWriter.debugLocation + File.separatorChar + dirs)).getParentFile().mkdirs();
File file = new File(new File(DebuggingClassWriter.debugLocation), dirs + ".class");
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
try {
out.write(b);
} finally {
out.close();
}
// 使用asm技术生成class文件
if (DebuggingClassWriter.traceCtor != null) {
file = new File(new File(DebuggingClassWriter.debugLocation), dirs + ".asm");
out = new BufferedOutputStream(new FileOutputStream(file));
try {
ClassReader cr = new ClassReader(b);
PrintWriter pw = new PrintWriter(new OutputStreamWriter(out));
ClassVisitor tcv = (ClassVisitor)DebuggingClassWriter.traceCtor.newInstance(null, pw);
cr.accept(tcv, 0);
pw.flush();
} finally {
out.close();
}
}
} catch (Exception var17) {
throw new CodeGenerationException(var17);
}
}
return b;
}
}));
}
static {
if (debugLocation != null) {
System.err.println("CGLIB debugging enabled, writing to '" + debugLocation + "'");
try {
Class clazz = Class.forName("org.objectweb.asm.util.TraceClassVisitor");
traceCtor = clazz.getConstructor(ClassVisitor.class, PrintWriter.class);
} catch (Throwable var1) {
}
}
}
最后,执行主程序里的firstInstance,最后会调用ReflectUtils.newInstance来实例化代理类对象,然后返回该代理类对象。
至此,CGLIB创建代理类创建流程结束,整个过程实现更复杂,生成代理类相比JDK动态代理效率低。
2.2调用代理对象
由第一步的3.1场景生成的代理类class文件可以看出,执行的是class文件中的sayHello方法,
public final void sayHello() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
} else {
super.sayHello();
}
}
var10000获取到的就是CGLibProxy对象,所以最终会调用CGLibProxy的intercept方法,该方法里,我们用了method.invoke通过反射机制调用了目标类的原始方法。
2.3类MethodProxy中invoke和invokeSuper执行源码分析及区别
在网上或者实际使用中,会经常看到在代理的拦截方法intercept中会通过methodProxy.invokeSuper来执行目标类的原始方法,使用它的作用是什么?以及相比于method.invoke有哪些优势?不着急,我们先根据源码搞懂它的原理。
首先,我们通过实际的例子,先看下使用methodProxy.invokeSuper会生成那些代理class文件。修改CGLibProxy的intercept方法,如下,
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 检查权限
checkPopedom();
Object obj = null;
try {
// 前置通知
before();
// obj = methodProxy.invoke(proxy, args);
obj = methodProxy.invokeSuper(proxy, args);
// 后置通知
after();
} catch (Exception e) {
// 异常通知
exception();
} finally {
// 方法返回前通知
beforeReturning();
}
return obj;
}
然后执行如下代码,
package com.test.proxy;
import net.sf.cglib.core.DebuggingClassWriter;
public class ProxyPerformanceTest {
public static void main(String[] args) {
// 该方法是为了生成由CGLIB生成的代理对象CLASS文件
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");
System.out.println("-----------CGLibProxy not use interface start-------------");
HelloWorld helloWorldCglib = (HelloWorld) new CGLibProxy().createProxy(new HelloWorld());
helloWorldCglib.sayHello();
System.out.println("-----------CGLibProxy not use interface end-------------");
}
}
执行结果如下,
-----------CGLibProxy not use interface start-------------
CGLIB debugging enabled, writing to 'D:\class'
CGLibProxy:检查权限 checkPopedom()!
CGLibProxy:before method invoke...
say HelloWorld
CGLibProxy:after method invoke...
CGLibProxy:beforeReturning method invoke...
-----------CGLibProxy not use interface end-------------
并生成如下三个class文件:
HelloWorld$$EnhancerByCGLIB$$74b9b49$$FastClassByCGLIB$$40d2459c.class
HelloWorld$$EnhancerByCGLIB$$74b9b49.class
HelloWorld$$FastClassByCGLIB$$212e5eaf.class
在这里,先提前说明下这三个文件是什么,
HelloWorld$$EnhancerByCGLIB$$74b9b49.class是实际生成的代理类;
HelloWorld$$FastClassByCGLIB$$212e5eaf.class是被代理类HelloWorld的FastClass;
HelloWorld$$EnhancerByCGLIB$$74b9b49$$FastClassByCGLIB$$40d2459c.class是代理类HelloWorld$$EnhancerByCGLIB$$74b9b49.class的FastClass。
注意,Cglib动态代理执行代理方法效率之所以比JDK的高是因为Cglib采用了FastClass机制,它的原理简单来说就是:为代理类和被代理类各生成一个Class(就是上面的两个FastClass的class文件),这个Class会为代理类或被代理类的方法分配一个index(int类型)。 这个index当做一个入参,FastClass就可以直接定位要调用的方法直接进行调用,这样省去了反射调用,所以调用效率比JDK动态代理通过反射调用高。
这么说可能比较难以理解,我们来看下代理类执行的过程就知道了。
FastClass并不是跟代理类一块生成的,而是在第一次执行MethodProxy的invoke/invokeSuper时生成的并放在了缓存中。
执行MethodProxy的invoke/invokeSuper前首先调用MethodProxy的init()方法创建FastClass文件,如下,
private void init() {
if (this.fastClassInfo == null) {
synchronized(this.initLock) {
if (this.fastClassInfo == null) {
MethodProxy.CreateInfo ci = this.createInfo;
MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();
// 如果缓存中有就取出,没有就生成新的FastClass
fci.f1 = helper(ci, ci.c1);
fci.f2 = helper(ci, ci.c2);
// 获取方法的index
fci.i1 = fci.f1.getIndex(this.sig1);
fci.i2 = fci.f2.getIndex(this.sig2);
this.fastClassInfo = fci;
this.createInfo = null;
}
}
}
}
private static class FastClassInfo {
// 被代理类FastClass
FastClass f1;
// 代理类FastClass
FastClass f2;
// 被代理类的方法签名(index)
int i1;
// 代理类的方法签名
int i2;
private FastClassInfo() {
}
}
invoke和invokeSuper方法源码如下,
public Object invoke(Object obj, Object[] args) throws Throwable {
try {
this.init();
MethodProxy.FastClassInfo fci = this.fastClassInfo;
// 调用被代理类FastClass的invoke
return fci.f1.invoke(fci.i1, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
} catch (IllegalArgumentException var5) {
if (this.fastClassInfo.i1 < 0) {
throw new IllegalArgumentException("Protected method: " + this.sig1);
} else {
throw var5;
}
}
}
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
this.init();
MethodProxy.FastClassInfo fci = this.fastClassInfo;
// 调用代理类FastClass的invoke
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
}
}
invoke和invokeSuper方法都会调用各自FastClass的invoke方法,有什么区别呢,上面可以debug看下f1,f2,i1,i2返回的结果,再来看下生成的两个FastClass,如下:
被代理类FastClass的class文件文件内容如下,
package com.test.proxy;
import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.reflect.FastClass;
public class HelloWorld$$FastClassByCGLIB$$212e5eaf extends FastClass {
public HelloWorld$$FastClassByCGLIB$$212e5eaf(Class var1) {
super(var1);
}
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case 1535311470:
if (var10000.equals("sayHello()V")) {
return 0;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return 1;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return 2;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return 3;
}
}
return -1;
}
public int getIndex(String var1, Class[] var2) {
switch(var1.hashCode()) {
case -2012993625:
if (var1.equals("sayHello")) {
switch(var2.length) {
case 0:
return 0;
}
}
break;
case -1776922004:
if (var1.equals("toString")) {
switch(var2.length) {
case 0:
return 2;
}
}
break;
case -1295482945:
if (var1.equals("equals")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("java.lang.Object")) {
return 1;
}
}
}
break;
case 147696667:
if (var1.equals("hashCode")) {
switch(var2.length) {
case 0:
return 3;
}
}
}
return -1;
}
public int getIndex(Class[] var1) {
switch(var1.length) {
case 0:
return 0;
default:
return -1;
}
}
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
HelloWorld var10000 = (HelloWorld)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
var10000.sayHello();
return null;
case 1:
return new Boolean(var10000.equals(var3[0]));
case 2:
return var10000.toString();
case 3:
return new Integer(var10000.hashCode());
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
HelloWorld var10000 = new HelloWorld;
HelloWorld var10001 = var10000;
int var10002 = var1;
try {
switch(var10002) {
case 0:
var10001.<init>();
return var10000;
}
} catch (Throwable var3) {
throw new InvocationTargetException(var3);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
public int getMaxIndex() {
return 3;
}
}
因为fci.f1.getIndex(this.sig1)获取到的index为0,所以如果CGLibProxy中的intercept中执行MethodProxy的invoke方法时,根据刚才的index为0,实际调用的是var10000.sayHello(),然后调用代理类中的sayHello(),然后调用的CGLibProxy中的intercept,然后再执行其中的MethodProxy的invoke方法,这样形成了一个死循环。所以说,在CGLibProxy中的intercept中执行MethodProxy的invoke方法,会形成死循环,应避免使用MethodProxy的invoke方法。
代理类FastClass的class文件文件内容如下,
package com.test.proxy;
import com.test.proxy.HelloWorld..EnhancerByCGLIB..74b9b49;
import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.reflect.FastClass;
public class HelloWorld$$EnhancerByCGLIB$$74b9b49$$FastClassByCGLIB$$40d2459c extends FastClass {
public HelloWorld$$EnhancerByCGLIB$$74b9b49$$FastClassByCGLIB$$40d2459c(Class var1) {
super(var1);
}
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case -2055565910:
if (var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
return 11;
}
break;
case -1882565338:
if (var10000.equals("CGLIB$equals$1(Ljava/lang/Object;)Z")) {
return 20;
}
break;
case -1457535688:
if (var10000.equals("CGLIB$STATICHOOK1()V")) {
return 10;
}
break;
case -1411842725:
if (var10000.equals("CGLIB$hashCode$3()I")) {
return 17;
}
break;
case -894172689:
if (var10000.equals("newInstance(Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 4;
}
break;
case -623122092:
if (var10000.equals("CGLIB$findMethodProxy(Lnet/sf/cglib/core/Signature;)Lnet/sf/cglib/proxy/MethodProxy;")) {
return 15;
}
break;
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return 3;
}
break;
case -419626537:
if (var10000.equals("setCallbacks([Lnet/sf/cglib/proxy/Callback;)V")) {
return 7;
}
break;
case 291273791:
if (var10000.equals("CGLIB$sayHello$0()V")) {
return 19;
}
break;
case 560567118:
if (var10000.equals("setCallback(ILnet/sf/cglib/proxy/Callback;)V")) {
return 9;
}
break;
case 811063227:
if (var10000.equals("newInstance([Ljava/lang/Class;[Ljava/lang/Object;[Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 5;
}
break;
case 973717575:
if (var10000.equals("getCallbacks()[Lnet/sf/cglib/proxy/Callback;")) {
return 14;
}
break;
case 1221173700:
if (var10000.equals("newInstance([Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 6;
}
break;
case 1230699260:
if (var10000.equals("getCallback(I)Lnet/sf/cglib/proxy/Callback;")) {
return 13;
}
break;
case 1306468936:
if (var10000.equals("CGLIB$toString$2()Ljava/lang/String;")) {
return 16;
}
break;
case 1535311470:
if (var10000.equals("sayHello()V")) {
return 8;
}
break;
case 1584330438:
if (var10000.equals("CGLIB$SET_STATIC_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
return 12;
}
break;
case 1800494055:
if (var10000.equals("CGLIB$clone$4()Ljava/lang/Object;")) {
return 18;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return 0;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return 1;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return 2;
}
}
return -1;
}
public int getIndex(String var1, Class[] var2) {
switch(var1.hashCode()) {
case -2012993625:
if (var1.equals("sayHello")) {
switch(var2.length) {
case 0:
return 8;
}
}
break;
case -1983192202:
if (var1.equals("CGLIB$sayHello$0")) {
switch(var2.length) {
case 0:
return 19;
}
}
break;
case -1776922004:
if (var1.equals("toString")) {
switch(var2.length) {
case 0:
return 1;
}
}
break;
case -1295482945:
if (var1.equals("equals")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("java.lang.Object")) {
return 0;
}
}
}
break;
case -1053468136:
if (var1.equals("getCallbacks")) {
switch(var2.length) {
case 0:
return 14;
}
}
break;
case -124978609:
if (var1.equals("CGLIB$equals$1")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("java.lang.Object")) {
return 20;
}
}
}
break;
case -60403779:
if (var1.equals("CGLIB$SET_STATIC_CALLBACKS")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 12;
}
}
}
break;
case -29025555:
if (var1.equals("CGLIB$hashCode$3")) {
switch(var2.length) {
case 0:
return 17;
}
}
break;
case 85179481:
if (var1.equals("CGLIB$SET_THREAD_CALLBACKS")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 11;
}
}
}
break;
case 94756189:
if (var1.equals("clone")) {
switch(var2.length) {
case 0:
return 3;
}
}
break;
case 147696667:
if (var1.equals("hashCode")) {
switch(var2.length) {
case 0:
return 2;
}
}
break;
case 161998109:
if (var1.equals("CGLIB$STATICHOOK1")) {
switch(var2.length) {
case 0:
return 10;
}
}
break;
case 495524492:
if (var1.equals("setCallbacks")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 7;
}
}
}
break;
case 1154623345:
if (var1.equals("CGLIB$findMethodProxy")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("net.sf.cglib.core.Signature")) {
return 15;
}
}
}
break;
case 1543336189:
if (var1.equals("CGLIB$toString$2")) {
switch(var2.length) {
case 0:
return 16;
}
}
break;
case 1811874389:
if (var1.equals("newInstance")) {
switch(var2.length) {
case 1:
String var10001 = var2[0].getName();
switch(var10001.hashCode()) {
case -845341380:
if (var10001.equals("net.sf.cglib.proxy.Callback")) {
return 4;
}
break;
case 1730110032:
if (var10001.equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 6;
}
}
case 2:
default:
break;
case 3:
if (var2[0].getName().equals("[Ljava.lang.Class;") && var2[1].getName().equals("[Ljava.lang.Object;") && var2[2].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 5;
}
}
}
break;
case 1817099975:
if (var1.equals("setCallback")) {
switch(var2.length) {
case 2:
if (var2[0].getName().equals("int") && var2[1].getName().equals("net.sf.cglib.proxy.Callback")) {
return 9;
}
}
}
break;
case 1905679803:
if (var1.equals("getCallback")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("int")) {
return 13;
}
}
}
break;
case 1951977610:
if (var1.equals("CGLIB$clone$4")) {
switch(var2.length) {
case 0:
return 18;
}
}
}
return -1;
}
public int getIndex(Class[] var1) {
switch(var1.length) {
case 0:
return 0;
default:
return -1;
}
}
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
74b9b49 var10000 = (74b9b49)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
return new Boolean(var10000.equals(var3[0]));
case 1:
return var10000.toString();
case 2:
return new Integer(var10000.hashCode());
case 3:
return var10000.clone();
case 4:
return var10000.newInstance((Callback)var3[0]);
case 5:
return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
case 6:
return var10000.newInstance((Callback[])var3[0]);
case 7:
var10000.setCallbacks((Callback[])var3[0]);
return null;
case 8:
var10000.sayHello();
return null;
case 9:
var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
return null;
case 10:
74b9b49.CGLIB$STATICHOOK1();
return null;
case 11:
74b9b49.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
return null;
case 12:
74b9b49.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
return null;
case 13:
return var10000.getCallback(((Number)var3[0]).intValue());
case 14:
return var10000.getCallbacks();
case 15:
return 74b9b49.CGLIB$findMethodProxy((Signature)var3[0]);
case 16:
return var10000.CGLIB$toString$2();
case 17:
return new Integer(var10000.CGLIB$hashCode$3());
case 18:
return var10000.CGLIB$clone$4();
case 19:
var10000.CGLIB$sayHello$0();
return null;
case 20:
return new Boolean(var10000.CGLIB$equals$1(var3[0]));
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
74b9b49 var10000 = new 74b9b49;
74b9b49 var10001 = var10000;
int var10002 = var1;
try {
switch(var10002) {
case 0:
var10001.<init>();
return var10000;
}
} catch (Throwable var3) {
throw new InvocationTargetException(var3);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
public int getMaxIndex() {
return 20;
}
}
因为fci.f2.getIndex(this.sig2)获取到的index为19,所以如果CGLibProxy中的intercept中执行MethodProxy的invokeSuper方法时,根据刚才的index为19,实际调用的是var10000.CGLIB$sayHello$0();,然后调用代理类中的CGLIB$sayHello$0(),然后调用的super.sayHello(),也就是调用被代理类HelloWorld的sayHello()方法。
再回看刚才的问题,在网上或者实际使用中,会经常看到在代理的拦截方法intercept中会通过methodProxy.invokeSuper来执行目标类的原始方法,使用它的作用是什么?以及相比于method.invoke有哪些优势?
很明显,invoke和invokeSuper的作用都是是为了创建代理类和被代理类的各自Fastclass类,Fastclass类是个class文件,里面主要是使用索引号index的方式,用index查找到相应的代理方法,实际的代理方法在代理类中。生成Fastclass只在第一次调用invoke或invokeSuper时生成,之后就用已生成的Fastclass就可以了。
invokeSuper通过索引号index调用的是被代理类(如上例中的HelloWorld.java)的目标方法。
invoke通过索引号index调用的是代理实现(CGLibProxy)中的拦截器,会在成死循环,报错:java.lang.StackOverflowError。这个问题怎么解决呢?解决办法就是在methodProxy.invoke方法的第一个参数传入被代理对象即可,具体如下例,修改CGLibProxy中的intercept方法,
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 检查权限
checkPopedom();
Object obj = null;
try {
// 前置通知
before();
obj = methodProxy.invoke(targetObject, args);
// 后置通知
after();
} catch (Exception e) {
// 异常通知
exception();
} finally {
// 方法返回前通知
beforeReturning();
}
return obj;
}
这块的原理就是,之前传代理对象proxy,在Fastclass中会调用代理类的拦截器,或造成死循环。如果传入targetObject之后,那么Fastclass中在调用var10000.sayHello()时,var10000就是targetObject,所以最终直接调用被代理对象的目标方法,而不会再到代理类中。在spring aop中就是这么用的。
使用cglib的invokeSuper要比jdk代理的method.invoke,从原理上要快得多。
三、总结
1.对于CGLIB代理,无论类是否实现接口,都可以代理,通过继承目标对象来生成代理对象,并重写目标对象的所有方法。所以CGLIB不能代理由final修饰的类或者方法。CGLIB代理是通过ASM开源包,对目标对象类的class文件加载进来,通过修改其字节码生成子类来处理。核心是实现MethodInterceptor接口,使用intercept()方法进行面向切面的处理,调用相应的通知。
2.对于JDK动态代理,因为其默认必须继承Proxy类,但是java不支持多继承,所以JDK代理只能代理接口实现类。JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。核心是实现InvocationHandler接口,使用invoke()方法进行面向切面的处理,调用相应的通知。
3.JDK和Cglib都是在运行期生成字节码,JDK是直接写Class字节码,Cglib使用ASM框架写Class字节码,Cglib代理实现更复杂,生成代理类比JDK效率低。
4.JDK调用代理方法,是通过反射机制调用,Cglib可以通过FastClass机制直接调用方法,Cglib执行效率更高。
扩展:
Spring 5.x 中 AOP 默认依旧使用 JDK 动态代理。
SpringBoot 2.x 开始,为了解决使用 JDK 动态代理可能导致的类型转化异常而默认使用 CGLIB。
在 SpringBoot 2.x 中,如果需要默认使用 JDK 动态代理可以通过配置项spring.aop.proxy-target-class=false来进行修改,proxyTargetClass配置已无效。
参考资料:
https:// blog.csdn.net/u013419838/article/details/93749164
https:// blog.csdn.net/u013277209/article/details/114707651
https:// blog.csdn.net/zhanghongzheng3213/article/details/81238900