00:00
下边呢,我们来学习一下spring的a op,就是我们常讲的面向切面编程,这个a op和我们前面讲那个IC或者叫Di是spring的两大基石。首先我们来看两个基本的问题,第一个,为什么需要A?第二个我们会说一下a op的基本概念。首先来看一个需求吧,我们通过这个需求呢来说,为什么需要LP需求上面呢有一个接口是一个数学计算器,里边有这样的四个方法,加减乘除,我底下呢提供一个这个接口的实现类,实现这个加减乘除这块看上去是比较容易的,但是我们旁边我们还有两个需求,需求一啊,为我们这个方法去做日志,这方法开始前跟结束前分别来。
01:00
打印正在发生的活动需求二,我们希望来做一个验证,就是说我们希望这个加减乘除只能够处理正数的运算。OK,我们看一下,首先来新建一个工程二。新建一个包。ARM as we could surrender a oed ho。新建一个借口。Ari calculator。四个方法分别是加、减、乘、除。Int。An。It。I'。
02:12
OK,提供这个接口的实现。那我们要实现这个加减乘除,我们看一下应该是。In result等于I加解6%什么呀?以这个实现也是相类似的。OK,以上的话呢,是我们给的这个接口,以及写的对这个接口的实现好了,看上去一切都相安无事,挺好的。
03:09
那下边的话呢,我们要来看一下,诶,我这两个额外需求怎么写,第一个完成一个日志方法,开始之前写一个日志,快结束之前也写一个日志,看这个日志哈,比方说这块我这样写take。The method and begins。With。I。就是这个方法呀,And,什么什么开始,OK,再做一个日志的method。
04:05
And,结束啊,以结束我们现在的话呢,我们为了做这个支持这个需求,我们必须在在每一个方法开始之前都干这样的一都干的一件事,对吧,于是我复制一下。叫什么呀?叫sub吧。哦。那看到这块的话,我们觉得这个日志这个代码是不是绝大部分的代码是相同的呀,我们只需要去改一个这个方法名,那结束之前那个日志也是相同的。C过来。
05:02
Some。Mo。因为。OK,我这样写好之后的话呢,我这个呃,整个这个需求,呃,日志这部分就完成了验证跟这个道理是一样的,我就不写了哈,现在的话呢,我们来测试一下。看一下抽出的效果。没房。A rely you。我arisme写错了是吧。二。I改一下。说为什么需要改啊,对于我们这种这个,嗯,需要完美的这个同学,当然需要改一下是吧,Calcul。
06:06
等于2ARITH calulator等于newrith calculator,然后叫arith calcator的爱的方法一,二,再调一个arith。Div方法,比方说。这个四。二。每一个都有返回值是吧。Set out。加。一这也会有一个啊,OK,一。
07:01
好了,那咱的结果的话呢,就是这样,我们看这方法开始之前这个方法是爱的方法,参数是一和二,结束的时候的话呢,结果是三,这个方法是div方法,开始的时候呢,参数是四和二,结束的时候的话呢,这个结果是二啊,这是我们后来在没方法里边打的这个结果啊,这样看这个写法是没问题的,我们翻过来,我们再来看我们这个接口的实现,大家看一下。我们这个实现大家觉得。我们会不会有一些需要吐槽的,有一些需要思考的呢?如果要是看的话,我们发现这个日志代码是不是都差不多呀,我在每一个方法开始之前,结束之前都需要来写这样的代码,很麻烦。而且我本来我这个I的方法非常的轻巧,写一个int result等于I加J,然后1RETURN就可以了吧,你现在的话呢,你混杂了很多额外的需求代码,但这个额外的需求是合理的,比方说做日志啊,线程这是合理的,你要是混杂进来之后的话,导致了我们以前的这个核心代码是不是。
08:14
嗯,变的这个占的这个整个的这方法的实现量就少了呀,那你维护起来的话也比较麻烦,这样做,嗯,至少有两个问题。第一个叫代码混乱。越来越多的非业务需求加入以后,原有的业务方法急剧膨胀,每个方法在处理核心逻辑的同时,还必须关注其他的关注点。就这个时候,哎,我这是一个爱的方法,本身我想写这个自己的逻辑就可以了啊,这样维护起来也比较方便,但是你当你加了日志,加了验证之后,这个代码比以前多了,那维护成本肯定要变高,比方说你以前要是找的话,一共两行代码好维护呢,还是四行代码好,四行代码好维护呢?
09:05
第二个问题。代码分散。以日志需求为例,为了满足单一的日志,不得不在多个模块里边多次加入重复的性能代码,如果日志需求发生变化的话,修改必须修改所有的模块,你看我现在我要求我在每一个之前都加上一个S硅谷。家,你怎么带啊?这么写吧,一个一个复制,很显然我们这里边的话呢,我们只有八个地方,大家觉得如果我要是在每一个类的每一个方法前面都需要干一个这样的事的话,就是是不是需要去改的地方,所以说又是一个不便不便于维护的地方。当然我们这块我们可以享受一下,这还是比较爽的是吧,能跑起来。嗯,没问题,好了,那针对于上述的这两个问题如何解决呢?我们跟大家讲,这个时候我们可以用a op的方式去解决,就是我们要说的这个面向切面编程,面向切面编程主要解决的就是这样的两个问题。
10:17
那我们首先用一个我们学过的方去实现这个a op叫动态代理,我们使用这个动态代理呢,可以解决上面这个问题,也就是我们利用这个动态代理实际上完成了a op的这样的一个实现。使用一个代理对象,将这个对象包起来,这样的话呢,在我这个实际上调用我任何方法之前,我可以插入其他代码,这不就可以了吗?OK,我们来实现一下,我用动态代理来写一下,那首先呢,我把这个名称改一下啊。这个叫带日志的。
11:07
好吧,这个我上去。不带日志,这个我们再给它还原回来。最轻巧最清纯的一个版本一下。现在呢,我们的目标就是,哎,我原实现了这个不动,然后我也能实现刚才那个日志。用什么呢?用。动态代理我来写一个,大家看一下哈,叫。Figure looking proxy。
12:05
啊,这个动态代理呢,我们讲账号基础的时候啊,有讲过,大家要是讲特别详细的去了解这个动态代理的话,可以参考我们以前的视频,那这块的话呢,我们就直接把这个代码给它写出来,首先我要写一个我要带的那个对象是什么,Thme calculator。这是什么呀?要看你的对象company,我们返回的呢,也是一个calculate at。返回一个日代理。Arithumatic calculator proxy now proxy。用动态代理的话,我们知道proxy等于什么呀?等于proxy.new proxy吧,需要三个参数分排版,第一个load。
13:15
Class loader等于ggage.at class.at class就是说第一个就是我这不是一个代理对象吗?代理对象啊,并不像我们正常的对象,正常对象是不是直接出来的呀,这个时候虚拟机有默认的类加载器,而且现在这个对象的话呢,是我这样凭空代理出来的,你得告诉我,我这个代理对象有哪一个类加载器来进行加载。代理对象有哪一个类加载器?负责。加载好,那第二个interfaces。
14:07
就是什么呀,导致我们实际上的这个,嗯。代理类使用哪些接口,即我们这个代理类。是什么类型,我们这个类型的话呢,就是new什么类型这个好了代理类。代理对象的情。其中有哪些方法?哦,是一个宿主对吧,不是这么写。好。最后一个我们说的这个什么呢叫嗯。
15:12
6VO handle。这块进行一个强转,大家说它干啥用的,因为你返回来一个代理对象,这边是有方法的,当我们调用这个代理对象方法的时候,应该怎么做,用的是它说当调用代理对象。其中港方法是。执行。代码就在这个里面,那我们首先的话呢,我们来做一个要的一句话一个。
16:01
然后呢,统一返回一个零。好了,之后的话,我们来测试一下方法。这个。我可以先给他助长。吧,看arithaticalcator等于newthal,注意我这个是什么呀,我这个是清纯的是吧,先看一下。这里边儿是不带任何人的了。没问题,好了,这个我们还给他写为他给然后呢。我在这个叫maththmeator proxy,等于诶等于它方号我就要传进去是吧。这个叫什么呀?你哪个对象我就要还进来,那我直接写一个口罩器吧。
17:05
把这个传进来,Charismme ccul target。点等于好的再回来怎么写CAL?Proxy target.at login。这块都用来写了。找一个看看效果。大家看反而是不是都是零啊是吧,而且这个引爆已经被触发了,这就说明我们这块搭建这个基本的这个骨架是没问题的,下面的话呢,具体具体实现这块有这个引没个方法,还有三个参数看怎么用的。At PAR。
18:00
这么写吧,Proxy是什么?正在返回的那个代理对象,一般情况下带in。方法中都不使用。对象就是说这个是正在返回那个,这个的话呢,我们很少使用,一会我们会解释一下啊,Method正在被调用的方法。正在被调用的方法,下一个A调用。方法是传入的参数OK,写一个吧,然后呢的answer。
19:01
加method name等于method.at name的method。什么呀,Begins?B。加s.s list OK,一个开始这边的话呢,我去执行这个方法。OK,执行方法什么执行方法book吧,执行他给的这个方法,正常执行。然后把object result等于它写上result后边日志。
20:00
The man。加。再看结果。大家看OK吧,那这个时候的话呢,我们再来看我们这个main方法,哎,我这个时候我实际上是用了这个动态代理搞定的,我们注意到我们原生的这个直线里边是不是清纯的呀,你这个直线跟这个直线比是不是清纯多了是吧,更加便于维护。那你过来,比方说这个时候我想来修改这个日志逻辑,我想加上一个爱的硅谷。CTRLCCTRLV这样改的话是不是也好改啊。
21:03
嗯,没问题没问题,诶我们看到呢,我们用这个动态代理是可以实现这样的一个功能的,那开发的时候能这样直接用吗。嗯,开发的时候啊,可以这样直接用,但是我们不建议这样用,为什么呢?因为这样写还是比较麻烦的,而且我们让一般的程序员去搞这个动态代理呢,这个要求也有一些高。那我们能不能用一种更简单的方式去实现呢?那完全可以用什么呀?就用到我们这个spring的a op就可以了。A op就是来干这个事,干这个事之前刚才讲的时候,这边还落了一个地儿,哪个地儿呢?我们说我们在这个里边啊,我们很少使用这个proxy,我来用一下,大家看看,比方说我写个简单的proxy是什么,大家看一看会怎么样。
22:02
执行。这是个什么东西啊?这是不是一个无限循环啊?嗯,啊,内存溢出了,为什么会这样,我们如果要是用这个proxy的话,你看我是不是调了proxy的一个to string方法呀,那我调这个to string方法的话,To string也是proxy对代理对象的一个方法吧,当我调这个方法的时候,它是不是又在调这个inb了,那如此它就是一个死循环,所以说我们在这个方法内部啊,是不会直接来调用proxy这个对象的某一个方法的,这块我们做一个了解就。可以了,OK。我们下面我们来说这块,这个叫a op,讲了这么多是吧,到底什么是a op。A op叫面向切面边程,Opop是面向对象编程,它俩不一样,A op是对面向对象编程的一个补充,A op的主要编程对象是切面,而切面是横切关注点的模块化,就是说我这个切面里边放的就是一个一个的横切关注点对应的方法。
23:25
我们使用A的时候呢,仍然需要定义公共的功能,但是我们不需要去修改受影响的类。这样的话,横切关注点被模块化到特殊的对象切面里面,我们要是再进行这个添加功能的话,就会变得特别简单,这个我们一会我们会通过一个图来说LP的好处,每个事物逻辑位移一个位置,代码不分散,便于维护和升级,业务模块更简洁,包含核心业务代码,只包含只包含这个刚才我们已经说过了,来我们通过这样的一个图来说啊,我们正常去写的话呢,我们这个业务逻辑啊,是这样的。
24:07
有验证,呃前置日志,然后核心方法后置日志,这是我们实际上写完之后的效果,这样写完之后的效果,我们看这个代码是不是非常的肿胀了非常多呀,于是的话呢,我们就把这个呃这样的验证啊日志啊,把它给单独都提出来,这这里边这一个一个具体需求的话,就是我们所谓那个叫横切关注点,那我把这个横切关注点拿出来,比方说验证放在一个里边,这个验证的话呢,就称之为一个切面日志啊,前置日志,后置日志。拿出来这个也称之为是一个切面,那么从上到下的哈,这叫什么叫抽取横切关注点,看到了吧,然后我这个横切关注点跟我们这块的这个业务,业务逻辑,这业务逻辑里边只包含核心代码哈,这要是往回去的话,我们就叫面向切面编程,就是说我由切面还有我这个纯净的业务逻辑,往回走的话,就会实现我们前面那个复杂的需求,嗯,面通过面向切面编程的方式实现这样的一个需求,看到了吧。
25:22
来说几个基本的概念,第一个切面,横切关注点,被模块化的特殊对象看。这一个一个的这个具体需求叫横切关注点,那么比方说这个日志,哎,我放一起了啊,这就叫日志前面验证,那我放一起了,当然我这块只有一个,只有一种验证啊,你也可以有多种验证,我我放一起的话,我们就称之为是验证切面,那切面就是横切关注点被模块化之后的特殊对象。
26:00
好了,通知。切面必须完成的工作,比方说必须要完成验证,必须完成日志,这就称之为是通知,具体的话,我们这里边的每一个方法,就是切面里面每一个方法都称之为是一个通知。好,目标被通知的对象,那这个就叫什么呀,目标。下一个叫代理,哎,这个混吧,之后这个家伙叫代理代理代理我们这块也能看到个反回的,不是proxy吗?它就是一个y get get name找一个。哎,这就叫什么叫代理对象OK。切面通知目标代理挺好理解的,我们来说两个不太好理解的,一个叫连接点,一个叫切点,这两个概念的话呢,大家先姑且一听,在我们后边讲具体四分a op的时候呢,我们还会来这个反复的强调它啊,叫连接点,你看连接点是什么意思啊,连接点程序执行的某个特定的位置。
27:23
这个连接点的话呢,是一个物理存在,比方说类的某个方法的调用前,调用后,这方法抛出异常的时候,那么在我们这块执行的时候,大家过来看啊,我这个里边比方说爱的方法执行之前啊,Some方法结束之前,这就称之为叫连接点。连接点有两个基本信息决定,第一个就是方法,这个方法表示程序的执行点,那还有一个叫相对点执行的方位,就是哪个方法执行前还是后,就这个意思,比方说这个I的方法啊,执行前的连接点,那这个执行点呢,我们叫这个方法,而方位呢,叫执行之前这个连接点,OK,它是一个具体的物理存在。
28:15
哪一个方法执行之前,或者哪个方法执行之后,或者哪一个方法抛出异常的时候叫连接点好切点。刚才我们知道啊,说每个类呢,会有多个连接点。连接点是客观客观存在的,看得见摸得着,而这个切点看不见摸不着啊。a op通过切点定位到特定的连接点。啥意思嘞?A op,我通过这样的一个切点,我能够定位到很多个连接点。嗯,我们就做这样的一个类比哈,连接点类似于数据库里边的一条条记录,而切点相当于我们的查询条件,切点和连接点并不是一一对应的关系,一个切点可以匹配多个连接点,那这个切点呢,我用这个point card接口来进行描述。
29:16
嗯,它使用类和方法作为连接点的查询条件,这个切点等我们到后边我们讲这个4a op编程的时候,大家会有更好的理解。好吧,这。
我来说两句