博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【设计模式】动态代理模式
阅读量:4080 次
发布时间:2019-05-25

本文共 3034 字,大约阅读时间需要 10 分钟。

上篇讲述了普通代理模式,今天来讲讲动态代理.说起动态代理,大家可能首先想到的就是Spring的AOP.我们天天在说AOP是通过动态代理实现的,那么动态代理到底是个什么呢?看完这篇文章你就会明白,同时也明白AOP到底是哪里用到了动态代理.

    首先,我们来看动态代理的定义:动态代理是在实现阶段不用关心代理谁,而在运行阶段才指定代理哪一个对象的一种特殊代理模式。

    接下来还是通过实例来学习吧,假定现有用户登录需求,在登录时需要校验验证码,校验验证码这个逻辑严格来讲其实是不属于登录逻辑的,只是一种额外的防刷校验,防止用户通过重复密码碰撞来实现密码破解,所以此时我们是不应该把他放进登录逻辑里,so,此处引入动态代理模式,校验逻辑交由代理类执行,接下来我们来看动态代理模式类图:

动态代理模式

    其中InvocationHandler是javareflect包中用于实现动态代理模式的一个核心接口,通过实现它并实现invoke接口来实现我们自己的逻辑.接下来我们来看具体代码实现:

    首先基,于抽象化,先定义接口IPlayer:

public interface IPlayer {
/** * 登录 */ void login(String captcha);}

    接下来我们看具体的玩家实现类Player:

public class Player implements IPlayer {
/** 玩家姓名 */ private String name; public Player(String name) { this.name = name; } @Override public void login(String captcha) { //此处校验登录密码等 System.out.println(MessageFormat.format("玩家{0}登录成功!!!!!", name)); }}

    可以看到我们玩家的实现中并不会对图形验证码做处理,只会执行自有登录逻辑.接下来我们来看核心类PlayerHandler:

public class PlayerHandler implements InvocationHandler {
private Object targetObj; /** * 代理方法,通过该方法返回具体的代理类 */ public Object proxy(Object sourceObj) { this.targetObj = sourceObj; return Proxy.newProxyInstance(sourceObj.getClass().getClassLoader(), sourceObj.getClass().getInterfaces(), this); } /** * 前置包装方法 此处业务为校验验证码 */ private void before(Method method, Object[] args) { System.out.println("执行前置方法"); String captcha = args[0].toString(); System.out.println(MessageFormat.format("用户的图形验证码是:{0}", captcha)); if (!"1111".equals(captcha)) { throw new IllegalArgumentException("图形验证码不正确"); } } /** * 后续包装方法 */ private void after(Method method, Object[] args) { System.out.println("执行后续方法"); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //执行前置方法 before(method, args); System.out.println(MessageFormat.format("动态代理执行器开始执行{0}方法!", method.getName())); //这一步会调用代理的具体对象执行具体方法 Object result = method.invoke(targetObj, args); //执行后续方法 after(method, args); return result; }}

    上述代码中注释已经很详细了,如有不明白的可以留言.此处我们直接来看client调用:

public static void main(String[] args) {    IPlayer player = (IPlayer) new PlayerHandler().proxy(new Player("white"));    player.login("2222");}

    执行结果如下:

执行前置方法用户的图形验证码是:2222Exception in thread "main" java.lang.IllegalArgumentException: 图形验证码不正确

    可以看到由于验证码并不匹配,所以在before方法中抛出异常,并未走到用户校验登录密码等逻辑,实现了提前业务处理.

    接下来看验证码校验通过的情况,将login入参改为”1111”,执行结果如下:

执行前置方法用户的图形验证码是:1111动态代理执行器开始执行login方法!玩家white登录成功!!!!!执行后续方法

    可以看到校验通过,用户登录成功.

    看到这里不知道大家有没有想起平时所用的Spring AOP?是否觉得我们平时用的AOP就是这样的(当然此处没有引入切面的概念).当然有朋友说了,我们的AOP可以在多个方法上使用,而且不用修改AOP的代码,那这里比如此处如果我们要扩展上面的程序,给玩家添加注册功能,也要校验验证码,我们的代理类也是不需要做任何修改的,只需要在IPlayer和Player中增加regist方法即可实现.

    看到这里大家是否明白了我们AOP中到底是怎么运用动态代理模式的了,就是我们写的AOP作为一个动态代理类,在执行完我们的预处理方法befor后,动态的获取到我们添加注解的方法所在的对象,之后调用我们添加注解的方法,之后再执行我们的后续处理after方法.

总结

  1. 隔离性:动态代理类不关心原有业务逻辑,只关心自己的前后处理逻辑
  2. 扩展性:增加其他业务时只要前后处理逻辑相同,不用修改代理类代码,只需新增业务接口即可

欢迎关注个人博客:blog.scarlettbai.com

你可能感兴趣的文章
String类的intern方法随笔
查看>>
【泛型】一个简易的对象间转换的工具类(DO转VO)
查看>>
1.随机函数,计算机运行的基石
查看>>
MouseEvent的e.stageX是Number型,可见as3作者的考虑
查看>>
在mc中直接加aswing组件,该组件还需最后用validate()方法
查看>>
移植Vim配色方案到Eclipse
查看>>
从超链接调用ActionScript
查看>>
谈谈加密和混淆吧[转]
查看>>
TCP的几个状态对于我们分析所起的作用SYN, FIN, ACK, PSH,
查看>>
网络游戏客户端的日志输出
查看>>
关于按钮的mouseOver和rollOver
查看>>
《多线程服务器的适用场合》例释与答疑
查看>>
Netty框架
查看>>
Socket经验记录
查看>>
对RTMP视频流进行BitmapData.draw()出错的解决办法
查看>>
FMS 客户端带宽计算、带宽限制
查看>>
在线视频聊天(客服)系统开发那点事儿
查看>>
SecurityError Error 2148 SWF 不能访问本地资源
查看>>
Flex4的可视化显示对象
查看>>
Flex:自定义滚动条样式/隐藏上下箭头
查看>>