此篇博客中说到的动态代理为通过 JDK 实现的动态代理。
在上篇 Java 静态代理 中我们说到了静态代理的缺点之一是「代理类需在程序编译前创建,不能在程序运行时动态创建被代理类的代理类」,此篇博客中我们仍将以「ZhangDeShuai 追求 YangHaoKan」为例介绍 Java 动态代理。
背景
上篇 Java 静态代理 中,如果 YangHaoKanMa 不在,ZhangDeShuai 就不能通过 YangHaoKanMa 追求 YangHaoKan 了。
足智多谋的 ZhangDeShuai 不能因为 YangHaoKanMa 不在就不追 YangHaoKan 了呀……于是就有了 ZhangDeShuai 找 yangHaoKanSister 的故事。
准备工作
根据代理模式的要求,我们先创建一个公共接口 Girl:
/**
* Girl 接口
*/
public interface Girl {
void WatchMovie();
}
然后创建一个接口的实现类 YangHaoKan:
/**
* 被代理类
*/
public class YangHaoKan implements Girl {
@Override
public void WatchMovie() {
System.out.println("杨好看说:你咋带我看恐怖片呢,我不开心了……");
}
}
分析问题
问题一: 我们已经将被代理类 YangHaoKan 创建好了,那么如何根据已经被加载到内存中的被代理类 YangHaoKan 动态创建其代理类呢?
问题二: 获得了代理类,我们如果通过调用代理类对象的方法时调用被代理类中的方法呢?
解决方案
针对「如何根据已经被加载到内存中的被代理类 YangHaoKan 动态创建其代理类」这个问题,我们建一个 ProxyFactory 工厂,如下所示:
public class ProxyFactory {
/**
* @param obj 被代理的对象,此例中为 YangHaoKan
* @return 代理类的类型
*/
public static Object getProxyInstance(Object obj) {
MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
myInvocationHandler.bind(obj);
// obj.getClass().getClassLoader():类加载器
// obj.getClass().getInterfaces():得到被代理类实现的全部接口
// myInvocationHandler:InvocationHandler 接口的实现类实例
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), myInvocationHandler);
}
}
针对「如何在调用代理类对象的方法时调用被代理类的同名方法」这个问题,我们通过实现 InvocationHandler 这个借口来解决,如下所示:
public class MyInvocationHandler implements InvocationHandler {
private Object obj1;
// 通过 bind() 方法将 Proxy.getProxyInstance(obj) 中的已经赋值的 obj 对象(YangHaoKan)赋给 obj1
public void bind(Object obj) {
this.obj1=obj;
}
/**
* @description 当我们调用代理类的对象调用方法时,会自动调用下述方法。
* 此例:执行 YangHaoKanSister.WatchMovie() 时,此方法会被调用
* @param proxy 代理类对象
* @param method 代理类对象的方法
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 下行代码是对业务的增强体现
System.out.println("我是 YangHaoKan 家属,你有钱吗?");
// 反射的使用:https://mindartisan.blog.csdn.net/article/details/105921930
Object returnValue = method.invoke(obj1, args);
// 下行代码是对业务的增强体现
System.out.println("我是 YangHaoKan 家属,你去送她花吧……");
return returnValue;
}
}
和上篇博客一样,附上 ZhangDeShuai 的代码:
public class ZhangDeShuai {
public static void main(String[] args) {
// 创建被代理类对象
YangHaoKan yangHaoKan = new YangHaoKan();
// YangHaoKanSister 是动态生成的代理类对象
Girl yangHaoKanSister= (Girl) ProxyFactory.getProxyInstance(yangHaoKan);
// 调用同名方法 WatchMovie(),自动执行 MyInvocationHandler 中的 invoke() 方法
yangHaoKanSister.WatchMovie();
}
}
运行结果:
我是 YangHaoKan 家属,你有钱吗?
杨好看说:你咋带我看恐怖片呢,我不开心了……
我是 YangHaoKan 家属,你去送她花吧……
说下动态代理它哪动了:看 ZhangDeShuai
代码中的 YangHaoKanSister
,这个对象就是我们根据被代理类动态生成的代理类,我们可以换成任何 YangHaoKanFamily 的成员,她爸、她妈、她姐姐、她妹妹、她大舅、她二舅……