动态代理设计模式

什么是动态代理

在理解一个设计模式前,可以先理解它所解决的业务场景。因为设计模式本身是一种思想,一种前辈总结下来高效率解决问题的思想。
我先来假设一个这样的场景,有一个抢票方法A,很好的封装了抢票的业务逻辑。这个方法A被系统中很多地方调用(系统中有多个地方可以抢票),如图:
方法A被系统中多个地方调用
随着系统业务的复杂化,现在要求在调用抢票方法A前,加一个权限验证。这个时候一般是不会在每个调用方法A前的地方加权限验证方法(即系统功能1,在调用方法A前,加一个权限验证;系统功能2,在调用方法A前,加一个权限验证;… 系统功能n,在调用方法A前,加一个权限验证),这样会导致重复代码,因为系统由多个程序员编写的,有的地方会改错或漏改,且当软件人员离职时,更容易出现漏改的地方。
这个也被称为代码编写的DRY原则:don’t repeat yourself(不要重复)
那么,可以将权限验证的方法,写在方法A中,上层调用者逻辑不变,下层通用方法A中加入权限验证,如图:
在这里插入图片描述
但是,这同样违反了一个代码编写原则:单一职责原则,即一个类或一个方法,应该是只负责一件事情,抢票方法A,那么它就应该只负责抢票的业务就好,不应该写入权限验证的业务,这个也叫高内聚。
遵循这个原则有什么好处呢,如果某一天,系统功能2调用抢票方法A,不需要加权限验证了,单单这个系统功能2调用不需要,其他调用的地方还需要,那么可行的做法是,在方法A加一个boolean参数,如果调用时为true,那么代码里验证权限,如果为调用时为false,那么代码里不验证权限。可以看到,因为这一个地方的修改,所有调用该方法A的地方,都要加一个参数,如图:
在这里插入图片描述
所以,这就是为什么要保持类的单一性原则的原因。那么,如果可以更好的保证这2个原则,最好还是可以配置项的,不用硬编码在代码里的,那就可以用到动态代理技术了。

动态代理的二种实现方式

其实有3中代理实现方式,但是其中一种是静态代理的,这里就不讨论了
现在,有一个通用的抢票接口ITicketManage,类中有一个通用的抢票方法ticket,实现类为TicketManageImpl
在这里插入图片描述
在这里插入图片描述
测试类PrimaryTest,有2个方法test1和test2,模拟调用通用抢票方法
在这里插入图片描述
上面就是普通的new对象,然后调用的方式。
现在,要实现

  1. 在调用抢票业务前,加上一段验证权限的逻辑,在抢票完成后,加上一段日志记录。
  2. 要求不侵入方法test本身里面的业务逻辑,也不能侵入方法ticket里的通用业务逻辑。
  3. 且要求,test2调用通用抢票方法ticket时,不执行权限验证。

实现jdk接口InvocationHandler

在jdk的java.lang.reflect包下,有一个接口InvocationHandler,实现这个接口的invoke方法,当调用目标代理对象时,会先来到该invoke方法。
在这里插入图片描述
注意,这里测试类通过动态代理对象来调用ticket方法了,不是原先new对象来调用了
在这里插入图片描述
运行结果截图
在这里插入图片描述
这样test1和test2中的业务代码没有改变,通用方法ticket中的业务代码也没有改变,这些业务代码都只要专注于做自己的事情就可以了,权限验证、log日志记录,通过在代理方法中来实现,spring的AOP编程,就是以动态代理为基础的。

实现cglib包下接口MethodIntercepter

在org.springframework.cglib.proxy包下,有一个接口MethodInterceptor,实现该接口,实现intercept方法
在这里插入图片描述
测试方法中,通过代理对象来调用目标ticket方法
在这里插入图片描述
这样就实现了既不入侵test方法中的业务逻辑,也不入侵ticket方法中的业务逻辑。

总结

通过动态代理的设计,可以很好的保证代码的DRY(不要重复)原则和单一职责原则,保证代码的高内聚、低耦合。spring的AOP编程思想,底层也是使用动态代理的方式,可以实现更加灵活的切面编程,这里就不展开讨论了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值