1.首先说明一点,这个动态代理只是一个名字,不要被这个名字吓坏了,不管什么代理不代理, 最终结果都是这个过程:
类(你创建)--->字节码(编译)--->内存中的Class(加载)--->堆中的对象(你创建), 然后我们 使用 对象调用方法
上边是一个常规过程,比较好理解,而这个动态代理是个什么回事儿呢? 他直接这样干:
字节码(代理生成)--->内存中的Class(加载)--->堆中的对象(代理给你创建) ,然后我们 使用 对象调用方法
其实 上边两个过程本身都是容易理解的,但是由于第二个过程, 它类不让你创建, 对象不需要你创建, 所以你不知道发生了什么,你也不知道这个类的结构是什么, 因此你对于它给你的对象也是感到很陌生,觉得很NB,其实也就是那回事儿,不要慌;接下来我们就来分析分析他到底给你生成了个啥类,给你创建了个啥对象:
2.JDK动态代理 : (代码可以先不看,我写的目的仅是为了你可以自证)
首先JDK动态代理需要你提供一个接口: UserService
public interface UserService {
void save();
}
提供一个实现类: UserServiceImpl
public class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.println("save()无参数方法");
}
}
再提供一个功能增强的类 MyInvocationHandler
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
/**
* 这是个增强方法,里边写得是增强逻辑,就是你要怎么增强
* @param proxy 代理对象
* @param method 被调用的方法
* @param args 方法参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName()+"开始调用了");
Object invoke = method.invoke(target, args);
System.out.println(method.getName()+"调用结束了");
return invoke;
}
}
可以了,接下来就由JDK登场了,他给我们提供了一个 类 工具类 Proxy
package java.lang.reflect;
public class Proxy implements java.io.Serializable {
//此处代码省略
}
接下来我们就用这个工具类创建代理:
public static void main(String[] args) throws IOException {
//生成的代理类保存到磁盘,在项目的com.sun.proxy下面生成$Proxy0.class类
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
//创建目标类对象
UserService target = new UserServiceImpl();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(target);
UserService proxyInstance = (UserService)Proxy.newProxyInstance(
UserServiceImpl.class.getClassLoader(),
UserServiceImpl.class.getInterfaces(),
myInvocationHandler);
//代理对象调方法
proxyInstance.save();
}
上边代码可以运行出来结果就是 目标类中的 save() 方法被代理对象增强了,我们需要做的是整理一下思路:
我们其实提供了三个东西 UserService / UserServiceImpl / MyInvocationHandler
然后JDK提供了一个东西 Proxy
最后 proxy.newProxyInstance(目标类的加载器,目标类的实现接口,增强类的对象) 创建了代理对象,
那既然创建了代理对象----->对象由Class而来---->Class由字节码而来---->字节码由类而来, 好的,接下来我们就是要拿出这个类:
//生成的代理类保存到磁盘,在项目的com.sun.proxy下面生成$Proxy0.class类
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
好的,我们看一下生成的类(需要反编译):其实你认真看看这个类,我就不用废话了,但是这个类有点长,我估计你不想看,那还是听我跟你掰扯掰扯:
其实呢下边这个类就是 JDK代理对象 所对应的类
public final class $Proxy0 extends Proxy implements UserService
你看它继承了 Proxy 实现了 UserService (说个题外话: 这其实也说明了为啥JDK动态代理必须要让目标类实现接口的原因,因为代理类已经有个父类Proxy了, java又不能多继承, 这个代理呢又需要和目标对象具有同样的功能,你说咋办, 那就跟目标对象实现同一个接口吧) 我们接着说: 其实这个代理类中 持有了一个增强类 MyInvocationHandler 的对象, 而这个MyInvocationHandler 的对象中又持有了一个 目标类对象, 大概就是这样:
代理对象-----持有----> MyInvocationHandler对象-----持有----> 目标类对象
所以我们每次使用代理对象调用方法的过程就是:
代理对象.save() -----触发-----> MyInvocationHandler对象.invoke() -----触发-----> 目标类对象.save()方法被调用
如果还是不懂了就看看下边的图片,或者下边的代码,接下来你往下拉一下滚动条,我们去看看JDK动态代理:
public final class $Proxy0 extends Proxy implements UserService {
private static Method m1;
private static Method m4;
private static Method m3;
private static Method m2;
private static Method m0;
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 void save(String var1) throws {
try {
super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void save() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
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"));
m4 = Class.forName("cn.proxy.dynamicProxy.ProxyTest.JDKProxy.UserService").getMethod("save", Class.forName("java.lang.String"));
m3 = Class.forName("cn.proxy.dynamicProxy.ProxyTest.JDKProxy.UserService").getMethod("save");
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());
}
}
}
3.CGLib动态代理 : (代码可以先不看,我写的目的仅是为了你可以自证)
我们来看CGLib动态代理需要我们提供什么:
首先是目标类: BookService
public class BookService {
public void add(){
System.out.println("add()方法执行了...");
}
}
然后是增强类: MyMethodInterceptor
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("前置增强");
methodProxy.invokeSuper(o,objects);
System.out.println("后置增强");
return null;
}
}
可以了,接下来CGLib闪亮登场: 它提供了一个工具类 Enhancer
package net.sf.cglib.proxy;
public class Enhancer extends AbstractClassGenerator {
//此处省去很多代码
}
接下来我们使用这个工具类来创建代理对象
public static void main(String[] args) throws IOException {
//下边这一句是为了生成代理类 是的 你没看错 是代理类 就是代理类, 真正开发的时候肯定是不需要这一句的
//有了代理类,其实你直接看代理类的源码自己也就懂了
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\classes");
//下边这些才是生成代理对象的代码
//1.创建工具类对象
Enhancer enhancer = new Enhancer();
//2.设置(代理的)父类
enhancer.setSuperclass(BookService.class);
//3.创建增强类对象
MyMethodInterceptor myMethodInterceptor = new MyMethodInterceptor();
//4.设置增强类对象
enhancer.setCallback(myMethodInterceptor);
//5.使用工具对象创建代理
BookService bookService = (BookService)enhancer.create();
//6.代理对象调用方法
bookService.add();
}
好了上边代码已经为我们创建了CGLib代理对象, 运行的结果就是 BookService 类的add() 方法被增强了,我们来整理一下思路:
我们其实提供了两个东西 BookService/ MyMethodInterceptor
然后CGLib提供了一个东西 Enhancer
最后 在设置了 父类 和 增强类对象 之后 : BookService bookService = (BookService)enhancer.create();
就可以创建一个代理对象
那既然创建了代理对象----->对象由Class而来---->Class由字节码而来---->字节码由类而来, 好的,接下来我们就是要拿出这个代理类:
//下边这一句是为了生成代理类 是的 你没看错 是代理类 就是代理类, 真正开发的时候肯定是不需要这一句的
//有了代理类,其实你直接看代理类的源码自己也就懂了
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\classes");
好的,我们看一下生成的类(需要反编译):其实你认真看看这个类,我就不用废话了,但是这个类有点长,我估计你不想看,那还是听我跟你掰扯掰扯:
其实呢下边这个类就是 CGLib代理对象 所对应的类
public class BookService$$EnhancerByCGLIB$$cdc837d extends BookService implements Factory
你看它继承了 BookService 实现了 Factory ,其实这个代理类中
1.持有了一个增强类 MyMethodInterceptor 的对象,
private MethodInterceptor CGLIB$CALLBACK_0;
2.代理类重写了父类方法,
public final void add() {
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$add$0$Method, CGLIB$emptyArgs, CGLIB$add$0$Proxy);
} else {
super.add();
}
}
3.这个代理类复制了父类方法,并且改了名字
final void CGLIB$add$0() {
super.add();
}
大概就是这样:
代理对象-----持有----> MyMethodInterceptor 对象
所以我们每次使用代理对象调用方法的过程就是:
代理对象.save() -----触发-----> MyMethodInterceptor 对象.intercept() -----触发-----> 代理对象.CGLIB$add$0() 重命名方法被调用
其实也就是说 这个CGLib代理对象很邪乎,它首先继承了 目标类 BookService, 重写了里边的方法,然后就是把所有要重写的方法对应生成一个CGLib方法 ( 长这样:CGLIB$add$0() ) ,而这个方法内部,调用了父类的被重写的方法, 简单理解来说,父类里边只有一套方法, 代理对象是作为子类重写一套,作为代理对象又代理一套,总共有两套方法;
如果还是不懂了就看看下边的图片,或者下边的CGLib代理对象的类的代码:
public class BookService$$EnhancerByCGLIB$$cdc837d extends BookService implements 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$add$0$Method;
private static final MethodProxy CGLIB$add$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$finalize$1$Method;
private static final MethodProxy CGLIB$finalize$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;
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("cn.proxy.dynamicProxy.ProxyTest.CGLibProxy.BookService$$EnhancerByCGLIB$$cdc837d");
Class var1;
Method[] var10000 = ReflectUtils.findMethods(new String[]{"finalize", "()V", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$finalize$1$Method = var10000[0];
CGLIB$finalize$1$Proxy = MethodProxy.create(var1, var0, "()V", "finalize", "CGLIB$finalize$1");
CGLIB$equals$2$Method = var10000[1];
CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
CGLIB$toString$3$Method = var10000[2];
CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
CGLIB$hashCode$4$Method = var10000[3];
CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4");
CGLIB$clone$5$Method = var10000[4];
CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
CGLIB$add$0$Method = ReflectUtils.findMethods(new String[]{"add", "()V"}, (var1 = Class.forName("cn.proxy.dynamicProxy.ProxyTest.CGLibProxy.BookService")).getDeclaredMethods())[0];
CGLIB$add$0$Proxy = MethodProxy.create(var1, var0, "()V", "add", "CGLIB$add$0");
}
final void CGLIB$add$0() {
super.add();
}
public final void add() {
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$add$0$Method, CGLIB$emptyArgs, CGLIB$add$0$Proxy);
} else {
super.add();
}
}
final void CGLIB$finalize$1() throws Throwable {
super.finalize();
}
protected final void finalize() throws Throwable {
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$finalize$1$Method, CGLIB$emptyArgs, CGLIB$finalize$1$Proxy);
} else {
super.finalize();
}
}
final boolean CGLIB$equals$2(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$2$Method, new Object[]{var1}, CGLIB$equals$2$Proxy);
return var2 == null ? false : (Boolean)var2;
} else {
return super.equals(var1);
}
}
final String CGLIB$toString$3() {
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$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy) : super.toString();
}
final int CGLIB$hashCode$4() {
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$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy);
return var1 == null ? 0 : ((Number)var1).intValue();
} else {
return super.hashCode();
}
}
final Object CGLIB$clone$5() 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$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy) : super.clone();
}
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -1574182249:
if (var10000.equals("finalize()V")) {
return CGLIB$finalize$1$Proxy;
}
break;
case -1422568652:
if (var10000.equals("add()V")) {
return CGLIB$add$0$Proxy;
}
break;
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return CGLIB$clone$5$Proxy;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return CGLIB$equals$2$Proxy;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return CGLIB$toString$3$Proxy;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return CGLIB$hashCode$4$Proxy;
}
}
return null;
}
public BookService$$EnhancerByCGLIB$$cdc837d() {
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) {
BookService$$EnhancerByCGLIB$$cdc837d var1 = (BookService$$EnhancerByCGLIB$$cdc837d)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);
BookService$$EnhancerByCGLIB$$cdc837d var10000 = new BookService$$EnhancerByCGLIB$$cdc837d();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Callback var1) {
CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
BookService$$EnhancerByCGLIB$$cdc837d var10000 = new BookService$$EnhancerByCGLIB$$cdc837d();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
BookService$$EnhancerByCGLIB$$cdc837d var10000 = new BookService$$EnhancerByCGLIB$$cdc837d;
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();
}
}