共计 3671 个字符,预计需要花费 10 分钟才能阅读完成。
写在之前
谈到代理模式,最罕用的应用场景莫过于 AOP 中的利用了,在探讨 AOP 的实现之前,先来聊聊什么代理模式。
动静代理有两种模式,动态代理和动静代理,大家先不必在意两者的概念,等理解本篇你将会发现其实两者差异不大。
动态代理
用一个简略的例子来剖析什么是动态代理,用买房张三卖房这件事儿为例,聊聊代理模式有何作用,为何如此应用如此频繁。
Subject 接口:用于对 被访问者 的抽象化(比方卖房这件事儿)
SubjectImpl:被访问者的具体实现(张三想要卖房)
SubjectProxy:被访问者的代理实现类,该类须要有一个 Subject 接口具体的实例。(比方房产中介,须要拿着张三受权才能够代理)
Client:访问者的形象。(比方李四想买房,自身是一个顾客)
代理类自身就是替被访问者做事的,李四想买房子,提了很多要求,比方朝南、学区房;房产中介(SubjectProxy)看张三家的房子刚好合乎李四预期,将张三的房子介绍给李四;相当于当一个中间人的意思。有人可能会说,就相似于一个介绍的活儿吗?非得让中介来吗?如果只是简略的介绍,还真不须要中介,然而中介能够帮忙跑贷款、帮忙把握合同等。
这样,张三只须要受权给中介,就能够一边做别的事儿,一边更加省心地实现交易。
下面的图牵强附会变成了如下的模式
被代理的形象接口——房子
public interface House {
/**
* 卖房子
*/
void sell();}
被拜访的类——张三的房子
public class HouseForZhangsan implements House {
@Override
public void sell() {System.out.println("zhangsan sell house…………");
}
}
代理类——房产中介
public class HouseProxy implements House {
private House house;
// 通过构造方法做到每次替不同的人代理
public HouseProxy (House house) {this.house = house;}
@Override
public void sell() {house = new HouseForZhangsan();
house.sell();}
}
测试类——交易场合
public class Test {public static void main(String[] args) {
// 结构具体的卖房者
House house = new HouseForZhangsan();
// 将张三交给中介代理
House houseForPerson = new HouseProxy(house);
houseForPerson.sell();}
}
还是回到 Spring AOP 模式中,其中 SubjectProxy 就像是 SubjectImpl 的中介,而 SubjectImpl 自身是零碎中的 JoinPoint 所在的对象(指标对象),牵强附会地为指标对象创立一个代理对象,实现切面的逻辑。
然而各位想想,市面上并不是只有房子卖呢,张三家里有一辆闲暇的车,也想卖,还能去找房产中介吗?
必定不能了。
于是催生出了专门用于车交易的中介,比方瓜子二手车(号称没有中间商赚差价,哈哈哈)、二手车之家等等。
<img src=”https://cdn.jsdelivr.net/gh/kaoyan-guide/personPic@main/imgBlog/spring/20210417205209.png” alt=” 二手车平台 ” style=”zoom:50%;” />
再比方万一张三忽然发现手机用久了,想卖掉二手手机,新的 iPhone,于是又呈现了各种各样的二手手机平台(其实实质也是一种中介)
<img src=”https://cdn.jsdelivr.net/gh/kaoyan-guide/personPic@main/imgBlog/spring/20210417205454.png” alt=” 二手手机 ” style=”zoom:40%;” />
……
……
等等,那有人可能会想,能不能搞一个中介,可能啥都卖呢?于是更加全面的二手平台应运而生了。
在这下面能够灵便的代理各种商品 (被代理对象),这就达到了一种 动静中介的成果。
对,没错,动静代理 曾经介绍完了。
<img src=”https://cdn.jsdelivr.net/gh/kaoyan-guide/personPic@main/imgBlog/spring/20210417210047.png” alt=”image-20210417210040941″ style=”zoom:50%;” />
开玩笑,持续聊聊 Spring AOP 是如何利用动静代理的。
动静代理
能够指定接口在运行期间动静的生成代理对象。(换句话说:无论你要卖什么,你来的时候都能够给你找一个对应的中介)
那么如何动静生成代理类呢?
须要借助两个工具,一个是 java.lang.reflect.Proxy
类 和 java.lang.reflect.InvocationHandler
,问题的关键在于如何实时的给客户产生一个满足要去的中介。
这个就是借助 InvocationHandler
来动静生成代理类,还是以下面中介为例,咱们权且讲要生成的代理类叫做 target
.
如何动静产生不同类型的中介?
第一步必定须要晓得此时替什么类型客户代理,然而又不能写得太死,咱们权且在生成代理类中先申明一个 被代理的对象。
第二步:通过某种形式将 被代理对象通过传入的形式传进来
第三步:将被代理对象与中介进行绑定。
/**
* 被代理的指标
*/
public Object target;
/**
* 绑定委托对象,并且生成代理类
* @param target
* @return
*/
public Object bind(Object target) {
this.target = target;
// 绑定该类实现的所有接口,获得代理类
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
上述几步部署实现之后,会明确中介要替什么人做事儿,中介做什么事儿,并且将中介与客户关联起来。
最初才是真正的替客户做事儿。
public class SellInvocationHandler implements InvocationHandler {
/**
* 被代理的指标
*/
public Object target;
/**
* 绑定委托对象,并且生成代理类
* @param target
* @return
*/
public Object bind(Object target) {
this.target = target;
// 绑定该类实现的所有接口,获得代理类
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {log.info("额定逻辑……");
return method.invoke(target, args);
}
}
还记得咱们之前说过的吗?
动静代理解决的只是灵便产生不同代理类(换句话说灵便搭配不同类型中介)
至于做什么类型事儿,和替什么人做什么事儿这两件事儿还是得存在。
因而依然须要申明 两个类。
做什么类型事儿
public interface House {
/**
* 卖房子
*/
void sell();}
替什么人做什么事儿
public class HouseForZhangsan implements House {
@Override
public void sell() {System.out.println("zhangsan sell house…………");
}
}
而后就能够欢快地进行交易了,每次有新的顾客来,就能够叫不同类型的中介来服务。
public class DynamicProxyTest {public static void main(String[] args) {SellInvocationHandler invocationHandler = new SellInvocationHandler();
// 将被拜访类和代理类互相绑定(将房产中介 与 房子卖者互相绑定)House house = (House) invocationHandler.bind(new HouseForZhangsan());
// 真正执行
house.sell();}
}
至此,咱们曾经实现了真正的灵便代理工作。
动静代理虽好,却不能解决所有的事件。比方,动静代理只能对实现了相应接口 (Interface) 的类应用,如果某个类没有实现任何的 Interface,就无奈应用动静代理机制为其生成相应的动静代理对象。