一、jdk的动态代理
这里拿jdk的动态代理来做例子,cglib的原理其实也是一样的
我们知道jdk的动态代理,必须实现接口.
1、定义接口
/**
* 明星类
*/
public interface Mingxing {
/**
* 唱歌
*/
public void sing() ;
/**
* 吃东西
*/
public void eat();
}
2. 定义实现类
public class Dengziqi implements Mingxing{
public void sing() {
System.out.println("我在唱歌");
}
public void eat() {
System.out.println("我在吃饭");
}
}
3.测试类
public class Test {
public static void main(String[] args) {
// 保存生成的代理类的字节码文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
final Dengziqi dengziqi = new Dengziqi();
Mingxing mingxing = (Mingxing) Proxy.newProxyInstance(Dengziqi.class.getClassLoader(), Dengziqi.class.getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("----之前----");
Object invoke = method.invoke(dengziqi, args);
System.out.println("----之后----");
return invoke;
}
});
mingxing.eat();
}
}
4.运行结果
看到当我们调用吃饭方法,还输出了2句话.
二、简单分析
1.我们先打印一下这个代理类
System.out.println(mingxing.getClass());
查看结果
这个类你去包中找实际上是找不到到的.因为这个类是动态生成的, 也就是$这种开头. 数字代表序号,因为可能生成多个这个样到类.用这个序号去做区分.
2.将生成的类文件保存磁盘
我们其实有在上面加上了一行代码
// 保存生成的代理类的字节码文件
System.getProperties().put(“sun.misc.ProxyGenerator.saveGeneratedFiles”, “true”);
运行以后,可以在目录下看到这个文件
这个文件其实就是代理类,打开这个文件,我们看下代理类的代码.
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sun.proxy;
import com.kangping.proxy.jdk.Mingxing;
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 Mingxing {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m4;
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 eat() 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 void sing() throws {
try {
super.h.invoke(this, m4, (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"));
m3 = Class.forName("com.kangping.proxy.jdk.Mingxing").getMethod("eat");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m4 = Class.forName("com.kangping.proxy.jdk.Mingxing").getMethod("sing");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
1.我们看到这个类首先实现了代理类的接口
public final class $Proxy0 extends Proxy implements Mingxing
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m4;
private static Method m0;
- 这些Method 是什么呢?
我们看到代码最下面有个静态代码块static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m3 = Class.forName("com.kangping.proxy.jdk.Mingxing").getMethod("eat"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m4 = Class.forName("com.kangping.proxy.jdk.Mingxing").getMethod("sing"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } }
我们可以发现这些method 对象其实就是代理接口(Mingxing)里面到方法对象
其中还有3个Object中的方法.
- 我们看其中的一个方法
public final void eat() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } }
super.h.invoke(this, m3, (Object[])null);
看到这个有没有点熟悉呢?
我们看到我们之前测试类中到代码
对对,这个 h 实际上就是InvocationHandler的实现类对象.
这个我们就很容易理解的这3个参数的含义
super.h.invoke(this, m3, (Object[])null);
proxy: 传的是this 实际上就是代理对象
method : 传的m3 实际上就是调用的方法对象
args : 方法参数,应为eat没有方法参数,这个是空
3.简单的看下proxy类
看下 创建代理类的这个方法
三、总结
动态代理主要分一下3个步骤
- 动态生成代理类字节码
- 通过类加载器把这个字节码加载到jvm
- 反射查创建对象返回
这个时候我们很容易理解,为什么创建代理对象到时候是3个参数
第一个参数是类加载器,用于加载代理类到字节码
第二个参数是代理实现接口,因为代理类需要实现相同到接口
第三个参数是InvocationHandler 对象. 在代理类方法中需要调用这个类中到方法