静态代理
代理-顾名思义就是自己不想做或者不方便的做的事情交给别人来做,自己就是被代理对象,被人就是代理对象。从实现上来说其实很简单-就是代理对象持有被代理对象的引用,调用的时候使用代理对象而不是被代理对象。这样做的目的通常是可以通过代理对象在执行时候可以在相应的方法上加上附加的功能。
来看一段代码:
//定义接口-被代理对象接口
public abstract class Person {
public abstract void marry();
}
//某一个被代理对象
public class DaiSi extends Person {
public void marry() {
System.out.printf("find a ugly girl \n");
}
}
//代理类
public class MatchMaker {
//持有被代理对象
private Person person;
public MatchMaker(Person person) {
this.person = person;
}
public void marry(){
//添加附加功能
System.out.println("find a girl..."); //前置执行代码
person.marry();
System.out.println("hei hei hei "); //后置执行代码
}
}
//测试类
public class Main {
public static void main(String[] args) {
MatchMaker matchMaker = new MatchMaker(new DaiSi());
//使用代理对象
matchMaker.marry();
}
}
输出:
find a girl...
find a ugly girl
hei hei hei
静态代理就到此为止,接下来重点说说jdk的动态代理
JDK动态代理
我们还是以上面的为例子:
//JDK动态代理需要定义接口
public interface Person {
public void marry();
}
//某一个Person还是保持不变
public class Daisi implements Person{
public void marry() {
System.out.println("love ugly girl!");
}
}
//JSK动态代理需要实现InvocationHandler接口
public class MatchMaker implements InvocationHandler {
//持有一个Object对象
private Object sub;
public MatchMaker() {
}
public MatchMaker(Object sub) {
//初始化Object
this.sub = sub;
}
//这个是自定义的方法,可有可无 只是用于更加方便的获取对象
public Object getInstance(){
//可以看出 jdk自带的动态代理是需要实现接口的
return Proxy.newProxyInstance(sub.getClass().getClassLoader(),sub.getClass().getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before calling + "+method.getName());
method.invoke(sub,args);
System.out.println( "after calling " + method.getName());
return null;
}
}
public class Main {
public static void main(String[] args) throws Exception{
Daisi ds = new Daisi();
MatchMaker matchMaker = new MatchMaker(ds);
Person person = (Person) matchMaker.getInstance();
System.out.println(person.getClass());//class com.sun.proxy.$Proxy0
person.marry();//实际上调用的是InvocationHandler 的方法
/**
* 动态代理的执行分为5个阶段:
* 1.拿到代理的对象 并获取他的接口:sub.getClass().getInterfaces()
* 2.JDK代理重新生成一个类,同时实现我们给代理对象的接口 class com.sun.proxy.$Proxy0
* 3.拿到代理对象的引用 //$Proxy0会持有 DaiDi类的引用
* 4.重新动态生成一个class的字节码
* 5.编译
*/
//下面的代码 可以用来将 com.sun.proxy.$Proxy0 生成class文件
byte[] data = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
FileOutputStream os = new FileOutputStream("E:/$Proxy0.class");
os.write(data);
os.close();
}
}
我们在来看看 $Proxy0.class 反编译 文件来印证我们上面说的过程:
//反编译的类实现了 Person 所以会有marry()方法
public final class $Proxy0 extends Proxy implements Person {
//这个m1 , m2 , m3 , m0是根据方法的个数生成的
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})).booleanValue();
} 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)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
//这个就是 marry方法
public final void marry() throws {
try {
//这里的super.h其实就是: protected InvocationHandler h;而这个变量 我们在$Proxy0的构造里面进行了初始化,所以可以看到 在这里实际上就是调用了InvocationHandler里面的invoke方法
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", new Class[]{Class.forName("java.lang.Object")});
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m3 = Class.forName("com.designModel.agentAndDynamicAgent.dynamicAgent.Person").getMethod("marry", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
总结:
JDK动态代理实现:
1.创建一个代理类实现InvocationHandler
2.持有被代理对象,或者直接用Object
3.对代理对象初始化,可以选择在构造中初始化,也可以选择其他方式
4.实现invoke方法
5.调用的时候 使用Proxy.newProxyInstance()获取对象,这个就是我们使用的代理对象
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
静态代理和动态代理的区别
静态代理在程序运行前就已经生成了代理类对象,而动态代理是在程序在运行是才生成的,然后通过类加载器将字节码加载到JVM中.