代理模式介绍
代理模式是面向对象中常见的设计模式之一。生活中有很多例子,比如说婚介所或者是房屋中介,就是代理模式的体现,中介往往作为中间人帮房东处理房子,而不是房东自己动手。
而代理模式又分为动态代理和静态代理。
这里我们就从羊村往事开始说起,仔细说说它与代理模式的关系...
背景介绍
众所周知,沸羊羊作为中国知名TG巨头之一,有一天他想把一束鲜花送给美羊羊,可是他又觉得不好意思,于是他就去叫喜羊羊帮他送花。这样代理关系就形成了,喜羊羊作为沸羊羊的代理,帮助他完成送花这件事。
静态代理简单示例
喜羊羊和沸羊羊同时需要实现了Sheep这个接口,因为他们都需要送花这个动作。
public interface Sheep {
void sendFlower();
}
沸羊羊要做的事就是送花
public class FeiYangYang implements Sheep {
//实现了Sheep类接口,重写送花方法
public void sendFlower() {
System.out.println("一束沸羊羊送的花");
}
}
而喜羊羊同样实现Sheep接口去送花,注意二者区别
XiYangYang的构造函数传入的参数其实是FeiYangYang的对象,因为喜羊羊只是作为代理
追根究底其实是feiYangYang在调用sendFlower()方法
public class XiYangYang implements Sheep {
//实例对象作为后续的代理
private FeiYangYang feiYangYang1;
//构造函数传入参数为沸羊羊,因为代理的对象是沸羊羊
public XiYangYang(FeiYangYang feiYangYang){
feiYangYang1 = feiYangYang;
}
public void sendFlower() {
feiYangYang.sendFlower();
}
}
测试:
public class Test01 {
public static void main(String[] args) {
//首先得有想送花的沸羊羊
FeiYangYang feiYY = new FeiYangYang();
//还有一个帮沸羊羊送花的喜羊羊
Sheep xiYY = new XiYangYang(feiYY);
//喜羊羊去送花了
xiYY.sendFlower();
}
}
从结果不难看出,虽然代码中写的是xiYY.sendFlower()
可是控制台的结果却是沸羊羊送的花,其中喜羊羊只是做了中介工作,并不是真正的送花羊!
为什么这么做?
有人说这不是脱裤子放屁吗?沸羊羊自己去送不就好了,这样做的目的在于可以将送花这个动作“独立”出来,可以在送花前后加上一些其他“东西”,就直接在代理的地方加上就行,否则重新写方法就显得很笨。
比如:喜羊羊在送花时顺便夸了沸羊羊
只需要在代理类中添加即可,不需要对原本类中的方法进行修改
public class XiYangYang implements Sheep {
//示例一个沸羊羊对象作为后续的代理对象,
private FeiYangYang feiYangYang1;
//构造函数传入参数为沸羊羊,因为代理的对象是沸羊羊
public XiYangYang(FeiYangYang feiYangYang){
//代理对象创建完了
feiYangYang1 = feiYangYang;
}
public void sendFlower() {
System.out.println("沸羊羊很帅的!");
feiYangYang1.sendFlower();
}
}
看看结果:
这样FeiYangYang类就只需要关注其根本的业务逻辑,其他杂事就可以将方法写在代理类中进行实现,比如一个做加法的方法,在调用方法前应该验证是否是数字,验证的步骤就可以放在代理类中进行实现。
至此便是静态代理模式的实例。
动态代理模式
静态代理看起来确实强大,但是毕竟这是写在编译完成之前的代码,换句话说这是“写死的”,在实际情况下肯定是无法满足需求的,我们需要的是在程序运行时生成,因此出现了动态代理。
一看到在运行时生成,那么毫无疑问肯定与反射脱不了干系。
相关技术支持
为了支持动态代理模式,JDK提供了Proxy类和InvocationHandler接口,通过这个类或者此接口实现类来生成动态代理类或者时动态代理对象。
怎么用?
官方要求需要动态代理类必须实现InvocationHandler接口
1.Proxy类提供了静态方法Proxy.newProxyInstance方法来获取代理对象
官方API文档:
2.InvocationHandler接口提供invoke方法来让代理类调用被代理类的方法并返回结果
官方API:
动态实例简单示例
那么故事继续,自从喜羊羊帮沸羊羊送完花后,喜羊羊终于和美羊羊在一起了(懂得都懂嗷hhh)。其他小羊都听说了这个神奇的事情,于是很多小羊也去找喜羊羊送花。随着业务越来越大,喜羊羊成立了送花公司(动态代理类),需要送花时,送花公司(动态代理类)再找员工(动态代理对象)去送花。
动态代理类(送花公司):
public class SendFlowerCompany implements InvocationHandler {
//首先需要实例一个员工准备接收送花业务
private Object employee;
//获得送花代理人(代理对象)的方法
public Object getInstance(Sheep sheep){
//给小羊安排送花员工
this.employee = sheep;
//通过拿到小羊对应的Class类
Class<?> clazz = this.employee.getClass();
//通过Proxy类提供的静态方法返回代理对象
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
/**
*重写invoke方法的目的是调用所代理的小羊接口的送花方法
* @param proxy 代理对象
* @param method 所代理的对象的方法
* @param args 需要的传入方法的参数
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在送花前的动作
before();
//通过method类提供的invoke方法调用所代理的类中的方法
Object result = method.invoke(this.employee,args);
//送完以后
after();
return result;
}
private void before(){
System.out.println("正在前往...");
}
private void after(){
System.out.println("行动结束...");
}
}
这次是懒羊羊(委托类)需要代理:
public class LanYangYang implements Sheep {
public void sendFlower() {
System.out.println("一束懒羊羊送的花");
}
}
测试:
public class Test02 {
public static void main(String[] args) {
//首先有一个懒羊羊,然后向送花公司请求服务
LanYangYang lanYangYang = new LanYangYang();
//首先得有一家送花公司
SendFlowerCompany sendFlowerCompany = new SendFlowerCompany();
//公司派出小羊为懒羊羊送花
Sheep employeeSheep = (Sheep) sendFlowerCompany.getInstance(lanYangYang);
employeeSheep.sendFlower();
}
}
结果:
至此,代理模式简单示例全部完成。
应用场景:Spring中Aop其实就是动态代理