首页 > 学院 > 开发设计 > 正文

【设计模式】动态代理模式

2019-11-06 08:07:26
字体:
来源:转载
供稿:网友

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

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

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

动态代理模式

    其中InvocationHandlerjavareflect包中用于实现动态代理模式的一个核心接口,通过实现它并实现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方法.

总结

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

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


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表