美文网首页程序员我的程序员自学之路
【框架】123:spring框架之面向切面编程

【框架】123:spring框架之面向切面编程

作者: 刘小爱 | 来源:发表于2020-08-29 10:20 被阅读0次

    ​今天是刘小爱自学Java的第123天。

    感谢你的观看,谢谢你。

    image

    学过很多面向XX编程,比如:

    面向过程编程,面向对象编程,面向接口编程,现在又是面向切面编程。

    但是不管如何,说来说去最终都是面向搜索引擎编程:面向百度编程,面向谷歌编程。

    今日学习内容安排:

    • AOP的引入,它到底是干嘛的?
    • AOP面向切面编程的思想概述,以及其常见术语的解释说明。
    • 两种AOP底层实现机制,同时也是对动态代理的再一次回顾学习。

    本来是打算将AOP知识点糅合到一篇文章中说明的,但是内容实在是太多了,写了近三千字一半都还没有学到,看来还是得慢慢来了。

    一、AOP的引入

    在学它之前,我们先要搞清楚它是干嘛的?

    dao层的方法基本都是增删改查,现在需要将所有方法都增加打印日志的功能,怎么办?

    如果我们每个方法里面都实现打印日志的功能,那也太复杂了,所以选择封装:

    image

    ①方法的封装

    我们将打印日志的功能封装到一个特有方法中,只需要在其它方法中调用该方法即可。

    但是这样就有一个很大的问题:

    dao层不只有userDao这个类,还有其它的类,也需要打印日志的功能,那怎么办?

    ②继承

    我们将打印日志的功能封装到一个类中,哪个类需要该方法就继承它即可,根据继承的原则:子类可以直接使用父类的方法。

    但是代码还是有问题,会出现代码的侵入。

    有没有方法可以不用修改类中方法的任何内容,就能实现方法的拓展?

    有,就是代理类的使用。

    注意:我举的这些例子都是伪代码,并不代表本身的业务逻辑,只是为了引出AOP的概念。

    image

    ③代码的侵入

    我们想给方法增加功能,使用继承的话都需要在对应方法中调用一个打印日志的方法。

    对方法本身修改了,有代码侵入,这是不符合OCP原则的,即对扩展开放,对修改关闭:你增强我的功能可以,但你不可以修改我

    ④使用代理

    在被代理类方法的基础上,拓展了一个打印日志的方法,本身的方法并没有发生任何变化。

    当然这里也是伪代码,并没有使用到动态代理,文章后面有更详细的一步步说明。

    我们以继承->代理的这种代码变化过程,引出AOP面向切面编程的概念。

    二、AOP概述及相关术语

    AOP全称Aspect Oriented Programing,翻译为面向切面编程,它是一种编程思想。

    我们都知道Java是一门面向对象编程的,即OOP全称Object Oriented Programming。

    AOP是OOP的延续,采取横向抽取机制,取代了传统纵向继承体系重复性代码的编写。

    简单的理解就是,它的作用和继承很像,但是它比继承要更强,用一句来说明AOP就是:

    基于原有目标对象,创建代理对象,在不修改原对象代码情况下,通过代理对象调用增强功能的代码,从而对原有方法进行增强 。

    关于AOP编程相关术语

    这些术语太生涩难懂了,每一个概念涉及到的知识面还很广,想要完全弄懂太难了。

    这里用一个例子来做说明,当然说明并不是很准确,但是对于新手来说方便理解记忆。

    image

    ①目标对象Target

    也就是需要被增强的对象。

    ②织入Weaving

    根据目标对象来创建代理对象的整个过程。

    ③代理对象Proxy

    即根据目标对象生成的代理对象。

    ④连接点JoinPoint

    所谓连接点是指那些被拦截到的点。

    就可以理解成对象中的方法,因为在Spring中,只支持方法类型的连接点。

    ⑤切入点PointCut

    所谓切入点就是连接点的一部分,即需要被拦截的连接点就是切入点。

    就可以理解成对象中需要增强的方法。

    ⑥通知Advice

    也就是增强的方法,例子中就是记录日志。

    通知分为前置通知、后置通知、异常通知、最终通知、环绕通知,这些后续会讲述。

    ⑦切面Aspect

    是通知和切入点的结合,通知和切入点共同定义了关于切面的全部内容。它的功能、在何时和何地完成其功能?说白了也就是:

    如何将增强方法添加到对应的方法中?

    此外还有一个术语叫:引介Introduction

    在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或属性,这个实际开发中基本涉及不到。

    AOP是基于动态代理的,基于两种动态代理机制:JDK动态代理和CGLIB动态代理。

    三、JDK动态代理实现AOP

    当然JDK动态代理很少使用,但是还是都写下,就当是对动态代理知识点的一个回顾。

    创建工厂类,该类可以获取代理类对象:

    image

    ①获取代理对象方法

    通过代理工厂的该方法就可以获取一个代理对象,为了通用性将返回值设定为Object。

    ②实例化代理类对象

    Proxy类的静态方法newProxyInstance(),根据方法名也能知道它是干嘛的,基本上动态代理的核心就是这个方法,参数有三个:

    • 目标对象的类加载器。
    • 目标对象实现的接口有哪些。
    • 调用处理器。

    当然,其代码编写有更优的方式,在Cglib动态代理中会说明,此处就使用最原始的方式。

    ③调用处理器

    InvocationHandler是一个接口,使用匿名内部类的方式获取其对象,其有一个方法叫invoke,该方法也有三个参数。

    如果方法名是我们需要增强的方法,那么我们给它增加一个功能,也就是④。

    如果不是,那么调用自己就好了,也就是method.invoke(target,args)。

    代码写完,做个测试

    image

    ⑤功能测试

    因为在动态代理中我们只选择对queryAll方法增强,所以用代理对象调用queryAll方法时会额外输出“记录日志”。

    而update方法不增强,就只会执行本身的功能,也就是“更新数据”。

    当然Jdk动态代理有一个局限,就是必须要有接口才行,所以就引出了CGLIB的使用。

    四、CGLIB动态代理

    CGLIB(Code Generation Library)是一个强大的,高性能的开源项目。

    其作用最直接的解释就是:不需要接口也可以实现动态代理。

    image

    ①获取代理对象生成器

    Enhancer,增强器的意思,也就是通过它来实现方法的增强。

    ②设置目标对象的Class对象

    该参数是目标对象的Class对象,不是类加载器,和Jdk动态代理有一定的区别。

    ③设置回调函数

    Jdk动态代理中的三个参数:类加载器、接口以及调用处理器,Cglib中不需要接口,该参数就相当于jdk动态代理中的调用处理器。

    setCallback方法的参数需要该接口的实现类对象,我们可以直接使用匿名内部类的方式作为参数,就和调用处理器一样。

    但是在本类中实现这个接口,不就有了一个现成的实现类么?而this表示谁调用我就是谁,本类或者本类的子类都行。

    这里进一步优化代码的编写,上述Jdk动态代理中也可以这样优化。

    ④intercept方法

    这是MethodInterceptor接口中的一个方法,intercept,翻译就是拦截的意思。

    其参数和Jdk中的调用处理器基本一样。

    ⑤生成代理对象

    enhancer调用create()生成代理对象。

    代码写完,做个测试

    image

    ⑥方法测试

    通过运行结果我们可以发现:和Jdk动态代理能达到一样增强选定方法的效果。

    注意:目标对象CustomerServicePlus并没有实现接口,如果使用Jdk动态代理是不行的,得使用Cglib动态代理才可以。

    最后

    谢谢你的观看。

    如果可以的话,麻烦帮忙点个赞,谢谢你。

    相关文章

      网友评论

        本文标题:【框架】123:spring框架之面向切面编程

        本文链接:https://www.haomeiwen.com/subject/rxvdsktx.html