AOP那些学术概念—通知、增强处理连接点(JoinPoint)切面(Aspect)

1、我所知道的AOP
初看起来,上来就是一大堆的术语,而且还有个拉风的名字,面向切面编程,都说是OOP的一种有益补充等等。一下子就会让你不知所措,心想着:怪不得很多人都和我说AOP多难多难。当我看进去以后,才发现:它就是一些在Java基础上的朴实无华的应用,包括IOC(见 《Spring IOC(依赖注入、控制反转)概念理解》),包括许许多多这样的名词,都是万变不离其宗而已。
2、为什么要用AOP
1)在我看来它的出现就是为了方便,国外一位很有名的大师说过,程序员都是“懒人”,因为他们把需要自己做的事情都让程序去做了。使用AOP能让你少写很多代码,就这一点理由就够充分了吧。
2)为了更清晰的逻辑,可以让你的业务逻辑只去关注自身的业务,而不去处理其他的事情。这些其他的事情包括:安全,事务,日志等等。
3、这些AOP术语初看起来都不好接受,慢慢来,很快就会弄明白。
  1. 通知、增强处理(Advice) 就是指你所需要的功能,也就是上面说的安全、事务、日志等。你得事先定义好,然后再在想用的地方用一下。包含Aspect的一段处理代码
  2. 连接点(JoinPoint) 是指spring允许你设置通知(Advice)的地方,这样的地方那可就真多了,基本上每个方法的前、后(两者都有也行),或抛出异常时都可以是连接点,spring只支持方法连接点。其他如AspectJ还可以在构造器或属性注入时设置连接点,只要记住,和方法有关的前前后后都是连接点。
  3. 切入点(Pointcut) 在连接点的基础上,来定义切入点,一个类里可能会有十几个方法,那就会相应的有十几个连接点,但是可能你并不想在所有方法的附近都使用通知(使用叫织入,下面再说),你只是想对其中几个使用通知,在调用这几个方法之前、之后或者抛出异常时干点什么,那么就用切入点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法。
  4. 切面(Aspect) 切面是通知和切入点的结合。现在发现了吧,没连接点什么事了,链接点就是为了让我们更好地去理解切点才引出来的概念,明白这个概念就行了。通知说明了干什么和什么时候干(什么时候通过方法名中的befor,after,around等就能知道),而切入点则是为了说明在哪干(指定到底是哪个方法),这就是一个完整的切面定义。
  5. 引入(introduction) 允许我们向现有的类中添加新方法属性。这不就是把切面(也就是新方法属性:通知定义的)用到目标类中吗?
  6. 目标(target) 引入中所提到的目标类,也就是要被通知的对象,也就是真正需要处理的业务逻辑,他可以在毫不知情的情况下,被咱们织入切面。而自己只专注于业务本身的逻辑处理。
  7. 代理(proxy) 整套AOP机制都是通过代理来实现的,这个一会儿给细说。
  8. 织入(weaving) 是指把切面应用到目标对象中来创建新的代理对象的过程。织入有三种方式,spring采用的是运行时,为什么是运行时,在上一文《Spring AOP开发漫谈之初探AOP及AspectJ的用法》中的第二个标题中提到。
  9. 目标对象 – 项目原始的Java组件。
  10. AOP代理  – 由AOP框架生成java对象。
  11. AOP代理方法 = advice + 目标对象的方法。
下面的图简化和形象的说明了AOP
Spring AOP开发漫谈之谈谈AOP那些学术概念 - 月上西楼 - 月上西楼

形象上看,AOP编程,就像是在做汉堡。

原始面包 目标对象的方法。业务组件就行了。

肉块 -  Advice

汉堡 -  AOP代理的方法。

将肉加到面包 引入

关键就是:切面定义了哪些连接点会得到通知。

4、我所理解的AOP原理

spring用代理类包裹切面,把它们织入到Spring管理的bean中,也就是说代理类伪装成目标类,它会截取对目标类中方法的调用,让调用者对目标类的调用都先变成伪装类,伪装类这就先执行了切面,再把调用转发给真正的目标bean。
现在可以自己想一想,怎么搞出来这个伪装类,才不会被调用者发现(过JVM的检查,JAVA是强类型检查,哪里都要检查类型)。

1)实现和目标类相同的接口。
       我也实现和你一样的接口,反正上层都是接口级别的调用,这样我就伪装成了和目标类一样的类(实现了同一接口),也就逃过了类型检查,到java运行期的时候,利用多态的后期绑定(所以spring采用运行时),伪装类(代理类)就变成了接口的真正实现,而它里面包裹了真实的那个目标类,最后实现具体功能的还是目标类,只不过是伪装类在之前干了点其他的事情(写日志,安全检查,事物等)。
这就好比某人委托你去办一件事情,每当此时,你的伪装类就会出来,当然委托者是分辨不出来是谁接的活儿,以为是你,这个伪装者虽然办不了这个事,但是它知道你能办,所以就答应下来了,并且收了点礼物(写日志),收完礼物了,得把事情给人家给办了,所以此时这个伪装者就会来找你这个真身了,最后处理事情的人还是你自己。但是你自己并不知道伪装者此时已经收了礼物了也做了一些额外的工作了,当你接到请求之后,你只是专心把剩余的事情处理好,而没有关注到底在最开始的时候谁才是真正的委托者。
顺着这个思路,如果这个类没实现一个接口呢,那它还怎么来伪装我呢?此时,压根儿就不会给他机会让他成为您的伪装者,那么就得用第二种代理方式来处理,创建一个目标类的子类,生个儿子,让儿子伪装自己。

2)生成子类调用。
       这次用子类来做伪装,当然这样也能逃过JVM的强类型检查,继承于本身的,当然也就查不出来了,子类重写了目标类的所有方法,当然在这些重写的方法中,不仅实现了目标类的功能,还在这些功能之前,实现了一些其他的(写日志,安全检查,事物等)。
这次的实现过程就是,子类先从父类中把所有的方法都继承下来,父类中所有的本事都被子类学会了,这样一来大家都会去找子类办事,但是子类每次处理和父类相同的事情之前,都要收点小礼物(写日志),然后才去办真正的事情。当然父亲是不知道儿子会这么干的。这里需要补充的是,某些本事是父亲所独有(final的),儿子学不会,学不了就办不了这个事,办不了这个事情,自然就不能收人家的礼物了。
前一种兄弟模式,spring会使用JDK的java.lang.reflect.Proxy类,它允许Spring动态生成一个新类来实现必要的接口,织入通知,并且把这些接口的任何调用都转发到目标类。
后一种父子模式,spring使用CGLIB库生成目标类的一个子类,在创建这个子类的时候,spring织入通知,并且把对这个子类的调用委托到目标类。
相比之下,还是兄弟模式好一些,它能更好地实现松耦合,尤其在今天都高喊着面向接口编程的情况下,父子模式只是在没有实现接口的时候,也能织入通知,应该当做一种例外。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值