Spring AOP—深入动态代理 万字详解(通俗易懂)
【摘要】 Spring 第四节 AOP——动态代理 万字详解!
目录
一、前言
- 第四节内容,up打算和大家分享Spring 动态代理 相关的内容;动态代理本质上是Spring AOP的一个前置的引入内容,一个AOP开篇之作,但它却相当重要,且本身难度较大。
- 注意事项——①代码中的注释也很重要;②不要眼高手低,自己跟着过一遍才真正有收获;③点击文章的侧边栏目录或者文章开头的目录可以进行跳转。
- 良工不示人以朴,up所有文章都会适时补充完善。大家如果有问题都可以在评论区进行交流或者私信up。感谢阅读!
二、动态代理快速入门
1.为什么需要动态代理? :
在日常开发中,往往存在这样一种需求——同时存在多个对象,这些对象对应的类都实现了同一接口,并且这些对象会去调用这个接口中的某一个方法,即多态,但是我们要求这几个对象在调用方法前,和调用方法后都要做一些业务处理,eg : 权限校验、事务管理、日志管理、安全校验等。
如果我们将这些相同的业务处理,都下沉到每一个具体的类,就会造成代码冗余,并且没有办法进行对象的统一管理和调用;而动态代理的出现,尤对其症地解决了这个问题。
2.动态代理使用案例:
up先在dynamic_proxy包下创建Animal接口,以及Cat, Dog类,Cat类和Dog类都实现了Animal接口。如下图所示 :
Animal接口代码如下 :
Cat类代码如下 :
Dog类代码如下 :
然后,我们创建一个AnimalProxyProvider类,见名知意,这个类可以提供一个Animal接口的代理对象,所以,该类中肯定会定义一个方法,用来返回Animal接口的代理实例,当然,这个方法稍微有点复杂,大家可以借助up的代码注释逐渐理解。
AnimalProxyProvider类代码如下 : (尤其注意匿名内部类中实现的invoke方法,其中的两条输出语句表示实现类对象相同的业务逻辑代码)
接着,up定义一个测试类,在测试类中定义一个单元测试方法,用以测试我们的动态代理是否生效。
TestAnimal类代码如下 :
运行结果 :
现在我们进行Debug断点调试,断点如下图所示 :
跳入eat()方法时会发现,IDEA直接跳到了AnimalProxyProvider类的getAnimalProxy方法中——匿名内部类实现的invoke方法里面,如下图所示 :
再往下执行便是通过反射调用对应的method,一直往下追,最终会跳到实现类的eat()方法中,如下图所示 :
3.动态代理的灵活性 :
动态代理的灵活性体现在哪里?
首先,被代理的对象是可变的。并且,代理对象所调用的方法也是可变的。
比方说,up在Animal接口中新定义了一个sleep方法,如下图所示 :
然后,up在Cat类中实现了sleep方法,如下图所示 :
接着,修改匿名内部类实现的invoke方法中的“业务逻辑”代码,如下图所示 :
最后,up在测试类中新定义一个单元测试方法,测试动态代理是否生效。
testSleep()方法代码如下 :
运行结果 :
三、深入动态代理
1.需求 :
定义Calculator接口,表示一个计算器,该接口中定义有可以完成简单加减乘除运算的方法,要求在每次执行运算方法前后,都打印出运算日志(运算法则和运算参数,以及运算结果)。
2.实现 :
2.1 接口和实现类
首先分析需求,既然要求在每次执行运算方法前后都打印出运算日志,显然我们会想到——仍是在匿名内部类实现的invoke方法中动手脚。
别的不说,先来定义Calculator接口和一个它的实现类。
Calculator接口如下 : (声明了“加减乘除”四个抽象方法)
定义一个实现类Calculator_Demo1,代码如下 :
2.2 提供代理对象的类
定义一个CalculatorProxyProvider类,与上文 “动态代理使用案例” 中定义的“提供代理对象的类”类似,都需要定义一个方法用于返回代理对象。
CalculatorProxyProvider类代码如下 :
2.3 测试类
最后,仍然是在测试类中定义一个单元测试方法,up新定义了一个TestCalculator类,代码如下 :
运行结果 :
3.引出AOP :
注意——
(1) CalculatorProxyProvider类的这段代码,如下图所示 :
在AOP中,称为“横切关注点”,也叫“前置通知”。
(2) 而下面的这段代码,如下图所示 :
从AOP的角度来看,也称为一个“横切关注点”,但也叫“返回通知”。
(3) 此外,异常处理——catch语句块中的这段代码,如下图所示 :
从AOP看,也称为一个“横切关注点”,但又称为“异常通知”。
(4) 最后,finally代码块中的内容,如下图所示 :
从AOP看,也称为一个“横切关注点”,但又称为“后置通知”。
分析一下我们方才写得代码,如下图所示 :
可以看到,无论是“前置通知”,“返回通知”,还是“异常通知”,“后置通知”。我们都只是草草地用了一条输出语句敷衍过去,这使得我们的代码不够牛逼,功能不够强大,且代码死板,不够灵活。
而作为一名OOP程序员,我们会容易联想到——假如此处的输出语句都替换成方法,用一个方法直接切入,那不就既满足灵活性,又可以实现强大的功能吗?
四、总结
- 🆗,以上就是Spring系列博文第四小节的全部内容了。
- 总结一下,我们应该明白动态代理究竟“动态”在哪里?—— 不止是被代理对象可变,且代理对象执行的方法也是可变的。我们还需要知道newProxyInstance方法的三个形参分别有什么作用,以及如何获取这三个形参(尤其是第三个形参——处理器对象的获取,用到了匿名内部类)。
- 总之,动态代理最大的价值,是在不改变原有代码的情况下进行了功能的拓展,即使用代理对象代替原来的对象完成业务逻辑。这篇博文其实是为了给“Spring—AOP”的分享做一个铺垫,我们以一个问题开始,又以一个问题结尾,也符合这篇博客的定位。
- 下一节内容——Spring AOP—切入点表达式和基于XML配置AOP,我们不见不散。感谢阅读!
System.out.println("END---------------------------------------");
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
作者其他文章
评论(0)