今天是刘小爱自学Java的第123天。 感谢你的观看,谢谢你。 学过很多面向XX编程,比如: 面向过程编程,面向对象编程,面向接口编程,现在又是面向切面编程。 但是不管如何,说来说去最终都是面向搜索引擎编程:面向百度编程,面向谷歌编程。 今日学习内容安排:
本来是打算将AOP知识点糅合到一篇文章中说明的,但是内容实在是太多了,写了近三千字一半都还没有学到,看来还是得慢慢来了。 一、AOP的引入在学它之前,我们先要搞清楚它是干嘛的? dao层的方法基本都是增删改查,现在需要将所有方法都增加打印日志的功能,怎么办? 如果我们每个方法里面都实现打印日志的功能,那也太复杂了,所以选择封装: ①方法的封装 我们将打印日志的功能封装到一个特有方法中,只需要在其它方法中调用该方法即可。 但是这样就有一个很大的问题: dao层不只有userDao这个类,还有其它的类,也需要打印日志的功能,那怎么办? ②继承 我们将打印日志的功能封装到一个类中,哪个类需要该方法就继承它即可,根据继承的原则:子类可以直接使用父类的方法。 但是代码还是有问题,会出现代码的侵入。 有没有方法可以不用修改类中方法的任何内容,就能实现方法的拓展? 有,就是代理类的使用。 注意:我举的这些例子都是伪代码,并不代表本身的业务逻辑,只是为了引出AOP的概念。 ③代码的侵入 我们想给方法增加功能,使用继承的话都需要在对应方法中调用一个打印日志的方法。 对方法本身修改了,有代码侵入,这是不符合OCP原则的,即对扩展开放,对修改关闭:你增强我的功能可以,但你不可以修改我。 ④使用代理 在被代理类方法的基础上,拓展了一个打印日志的方法,本身的方法并没有发生任何变化。 当然这里也是伪代码,并没有使用到动态代理,文章后面有更详细的一步步说明。 我们以继承->代理的这种代码变化过程,引出AOP面向切面编程的概念。 二、AOP概述及相关术语AOP全称Aspect Oriented Programing,翻译为面向切面编程,它是一种编程思想。 我们都知道Java是一门面向对象编程的,即OOP全称Object Oriented Programming。 AOP是OOP的延续,采取横向抽取机制,取代了传统纵向继承体系重复性代码的编写。 简单的理解就是,它的作用和继承很像,但是它比继承要更强,用一句来说明AOP就是: 基于原有目标对象,创建代理对象,在不修改原对象代码情况下,通过代理对象调用增强功能的代码,从而对原有方法进行增强 。 关于AOP编程相关术语 这些术语太生涩难懂了,每一个概念涉及到的知识面还很广,想要完全弄懂太难了。 这里用一个例子来做说明,当然说明并不是很准确,但是对于新手来说方便理解记忆。 ①目标对象Target 也就是需要被增强的对象。 ②织入Weaving 根据目标对象来创建代理对象的整个过程。 ③代理对象Proxy 即根据目标对象生成的代理对象。 ④连接点JoinPoint 所谓连接点是指那些被拦截到的点。 就可以理解成对象中的方法,因为在Spring中,只支持方法类型的连接点。 ⑤切入点PointCut 所谓切入点就是连接点的一部分,即需要被拦截的连接点就是切入点。 就可以理解成对象中需要增强的方法。 ⑥通知Advice 也就是增强的方法,例子中就是记录日志。 通知分为前置通知、后置通知、异常通知、最终通知、环绕通知,这些后续会讲述。 ⑦切面Aspect 是通知和切入点的结合,通知和切入点共同定义了关于切面的全部内容。它的功能、在何时和何地完成其功能?说白了也就是: 如何将增强方法添加到对应的方法中? 此外还有一个术语叫:引介Introduction 在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或属性,这个实际开发中基本涉及不到。 AOP是基于动态代理的,基于两种动态代理机制:JDK动态代理和CGLIB动态代理。 三、JDK动态代理实现AOP当然JDK动态代理很少使用,但是还是都写下,就当是对动态代理知识点的一个回顾。 创建工厂类,该类可以获取代理类对象: ①获取代理对象方法 通过代理工厂的该方法就可以获取一个代理对象,为了通用性将返回值设定为Object。 ②实例化代理类对象 Proxy类的静态方法newProxyInstance(),根据方法名也能知道它是干嘛的,基本上动态代理的核心就是这个方法,参数有三个:
当然,其代码编写有更优的方式,在Cglib动态代理中会说明,此处就使用最原始的方式。 ③调用处理器 InvocationHandler是一个接口,使用匿名内部类的方式获取其对象,其有一个方法叫invoke,该方法也有三个参数。 如果方法名是我们需要增强的方法,那么我们给它增加一个功能,也就是④。 如果不是,那么调用自己就好了,也就是method.invoke(target,args)。 代码写完,做个测试 ⑤功能测试 因为在动态代理中我们只选择对queryAll方法增强,所以用代理对象调用queryAll方法时会额外输出“记录日志”。 而update方法不增强,就只会执行本身的功能,也就是“更新数据”。 当然Jdk动态代理有一个局限,就是必须要有接口才行,所以就引出了CGLIB的使用。 四、CGLIB动态代理CGLIB(Code Generation Library)是一个强大的,高性能的开源项目。 其作用最直接的解释就是:不需要接口也可以实现动态代理。 ①获取代理对象生成器 Enhancer,增强器的意思,也就是通过它来实现方法的增强。 ②设置目标对象的Class对象 该参数是目标对象的Class对象,不是类加载器,和Jdk动态代理有一定的区别。 ③设置回调函数 Jdk动态代理中的三个参数:类加载器、接口以及调用处理器,Cglib中不需要接口,该参数就相当于jdk动态代理中的调用处理器。 setCallback方法的参数需要该接口的实现类对象,我们可以直接使用匿名内部类的方式作为参数,就和调用处理器一样。 但是在本类中实现这个接口,不就有了一个现成的实现类么?而this表示谁调用我就是谁,本类或者本类的子类都行。 这里进一步优化代码的编写,上述Jdk动态代理中也可以这样优化。 ④intercept方法 这是MethodInterceptor接口中的一个方法,intercept,翻译就是拦截的意思。 其参数和Jdk中的调用处理器基本一样。 ⑤生成代理对象 enhancer调用create()生成代理对象。 代码写完,做个测试 ⑥方法测试 通过运行结果我们可以发现:和Jdk动态代理能达到一样增强选定方法的效果。 注意:目标对象CustomerServicePlus并没有实现接口,如果使用Jdk动态代理是不行的,得使用Cglib动态代理才可以。 最后谢谢你的观看。 如果可以的话,麻烦帮忙点个赞,谢谢你。 |
|