从法外狂徒张三卖房引起的代理模式 |
您所在的位置:网站首页 › aop一般用在什么场景 › 从法外狂徒张三卖房引起的代理模式 |
写在之前
谈到代理模式,最常用的使用场景莫过于 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 所在的对象(目标对象),顺理成章地为目标对象创建一个代理对象,完成切面的逻辑。 但是各位想想,市面上并不是只有房子卖呢,张三家里有一辆空闲的车,也想卖,还能去找房产中介吗? 肯定不能了。 于是催生出了专门用于车交易的中介,比如瓜子二手车(号称没有中间商赚差价,哈哈哈)、二手车之家等等。 再比如万一张三突然发现手机用久了,想卖掉二手手机,新的 iPhone,于是又出现了各种各样的二手手机平台(其实本质也是一种中介) …… …… 等等,那有人可能会想,能不能搞一个中介,能够啥都卖呢?于是更加全面的二手平台应运而生了。 在这上面可以灵活的代理各种商品 (被代理对象),这就达到了一种动态中介的效果。 对,没错,动态代理已经介绍完了。 开玩笑,继续聊聊 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,就无法使用动态代理机制为其生成相应的动态代理对象。 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |