在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,经过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP能够对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度下降,提升程序的可重用性,同时提升了开发的效率。
java
能够经过预编译方式和运行期动态代理实如今不修改源代码的状况下给程序动态统一添加功能的一种技术。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,提升代码的灵活性和可扩展性,AOP能够说也是这种目标的一种实现。
程序员
面向切面编程(AOP是Aspect Oriented Program的首字母缩写) ,咱们知道,面向对象的特色是继承、多态和封装。而封装就要求将功能分散到不一样的对象中去,这在软件设计中每每称为职责分配。实际上也就是说,让不一样的类设计不一样的方法。这样代码就分散到一个个的类中去了。这样作的好处是下降了代码的复杂程度,使类可重用。 spring
可是人们也发现,在分散代码的同时,也增长了代码的重复性。什么意思呢?好比说,咱们在两个类中,可能都须要在每一个方法中作日志。按面向对象的设计方法,咱们就必须在两个类的方法中都加入日志的内容。也许他们是彻底相同的,但就是由于面向对象的设计让类与类之间没法联系,而不能将这些重复的代码统一块儿来。 数据库
也许有人会说,那好办啊,咱们能够将这段代码写在一个独立的类独立的方法里,而后再在这两个类中调用。可是,这样一来,这两个类跟咱们上面提到的独立的类就有耦合了,它的改变会影响这两个类。那么,有没有什么办法,能让咱们在须要的时候,随意地加入代码呢?这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。 编程
通常而言,咱们管切入到指定类指定方法的代码片断称为切面,而切入到哪些类、哪些方法则叫切入点。有了AOP,咱们就能够把几个类共有的代码,抽取到一个切片中,等到须要时再切入对象中去,从而改变其原有的行为。这样看来,AOP其实只是OOP的补充而已。OOP从横向上区分出一个个的类来,而AOP则从纵向上向对象中加入特定的代码。有了AOP,OOP变得立体了。若是加上时间维度,AOP使OOP由原来的二维变为三维了,由平面变成立体了。从技术上来讲,AOP基本上是经过代理机制实现的。 设计模式
AOP在编程历史上能够说是里程碑式的,对OOP编程是一种十分有益的补充。安全
首先面向切面编程是什么。就指是把逻辑代码和处理琐碎事务的代码分离开,以便可以分离复杂度。让人在同一时间只用思考代码逻辑,或者琐碎事务。代码逻辑好比是插入一条数据,那么琐碎事务就包括获取链接和关闭链接,事务开始,事务提交。切面就是指在大堆繁杂事务中的逻辑代码。而后举个例子:先假设你有一段逻辑代码要写~ 在这段代码以前要写log;代码完成以后要写log。结局就是一大堆的log代码就淹没了逻辑代码。aop的想法就是将非逻辑部分的代码抽离出来,只考虑逻辑代码就好了,我把框框画好,这里写前面的log,这里写逻辑,这里写后面的log。事实上用着嘛~ 我没用过。逻辑代码好像和非逻辑代码是分开在不一样文件的。我的以为跳文件也很烦躁。感受应该是系统大到某种程度才会须要这么严格的复杂度控制吧。--------------------------无责任吐槽分割线--------------------------(本故事纯属虚构,若有雷同纯属巧合)虽然我没用过,可是忽然想到我曾经在某个系统里见过这货。这个系统是这样的,使用了aop,将数据库的事务管理啊什么的都搞定了封印了。 可是,这个系统的log语句没有被封印,逻辑代码都还被logger.log("xxxxx")这样的语句给包围着。 若是说一个函数的话,可能就是有一半在作log,一个类有一半在作log。就算框架给框框画好了要用aop,也有人有办法不用,或者用很差。其实不用aop的框架的话,也能够把前面和后面的琐碎事务本身抽象一下也能分开,这虽然不用框架可是也有aop的意思,就把琐碎事务都压缩到一个前置函数和一个后置函数里面。
框架
初看aop,上来就是一大堆术语,并且还有个拉风的名字,面向切面编程,都说是OOP的一种有益补充等等。一会儿让你不知所措,心想着:怪不得不少人都和我说aop多难多难。当我看进去之后,我才发现:它就是一些Java基础上的朴实无华的应用,包括ioc,包括许许多多这样的名词,都是万变不离其宗而已。函数式编程
1就是为了方便,看一个国外颇有名的大师说,编程的人都是“懒人”,由于他把本身作的事情都让程序作了。用了aop能让你少写不少代码,这点就够充分了吧函数
2就是为了更清晰的逻辑,可让你的业务逻辑去关注本身自己的业务,而不去想一些其余的事情,这些其余的事情包括:安全,事物,日志等。
初看这么多术语,一会儿都很差接受,慢慢来,很快就会搞懂。
就是你想要的功能,也就是上面说的 安全,事物,日志等。你给先定义好把,而后在想用的地方用一下。
这个更好解释了,就是spring容许你使用通知的地方,那可真就多了,基本每一个方法的前,后(二者都有也行),或抛出异常时均可以是链接点,spring只支持方法链接点.其余如aspectJ还可让你在构造器或属性注入时都行,不过那不是咱关注的,只要记住,和方法有关的前先后后(抛出异常),都是链接点。
上面说的链接点的基础上,来定义切入点,你的一个类里,有15个方法,那就有几十个链接点了对把,可是你并不想在全部方法附近都使用通知(使用叫织入,之后再说),你只想让其中的几个,在调用这几个方法以前,以后或者抛出异常时干点什么,那么就用切点来定义这几个方法,让切点来筛选链接点,选中那几个你想要的方法。
切面是通知和切入点的结合。如今发现了吧,没链接点什么事情,链接点就是为了让你好理解切点,搞出来的,明白这个概念就好了。通知说明了干什么和何时干(何时经过方法名中的before,after,around等就能知道),而切入点说明了在哪干(指定究竟是哪一个方法),这就是一个完整的切面定义。
容许咱们向现有的类添加新方法属性。这不就是把切面(也就是新方法属性:通知定义的)用到目标类中吗
引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他能够在绝不知情的状况下,被我们织入切面。而本身专一于业务自己的逻辑。
怎么实现整套aop机制的,都是经过代理,这个一会给细说。
把切面应用到目标对象来建立新的代理对象的过程。有3种方式,spring采用的是运行时,为何是运行时,后面解释。
关键就是:切点定义了哪些链接点会获得通知
spring用代理类包裹切面,把他们织入到Spring管理的bean中。也就是说代理类假装成目标类,它会截取对目标类中方法的调用,让调用者对目标类的调用都先变成调用假装类,假装类中就先执行了切面,再把调用转发给真正的目标bean。
如今能够本身想想,怎么搞出来这个假装类,才不会被调用者发现(过JVM的检查,JAVA是强类型检查,哪里都要检查类型)。
1.实现和目标类相同的接口,我也实现和你同样的接口,反正上层都是接口级别的调用,这样我就假装成了和目标类同样的类(实现了同一接口,咱是兄弟了),也就逃过了类型检查,到java运行期的时候,利用多态的后期绑定(因此spring采用运行时),假装类(代理类)就变成了接口的真正实现,而他里面包裹了真实的那个目标类,最后实现具体功能的仍是目标类,只不过假装类在以前干了点事情(写日志,安全检查,事物等)。
这就比如,一我的让你办件事,每次这个时候,你弟弟就会先出来,固然他分不出来了,觉得是你,你这个弟弟虽然办不了这事,可是他知道你能办,因此就答应下来了,而且收了点礼物(写日志),收完礼物了,给把事给人家办了啊,因此你弟弟又找你这个哥哥来了,最后把这是办了的仍是你本身。可是你本身并不知道你弟弟已经收礼物了,你只是专心把这件事情作好。
顺着这个思路想,要是自己这个类就没实现一个接口呢,你怎么假装我,我就压根没有机会让你搞出这个双胞胎的弟弟,那么就用第2种代理方式,建立一个目标类的子类,生个儿子,让儿子假装我
2.生成子类调用,此次用子类来作为假装类,固然这样也能逃过JVM的强类型检查,我继承的吗,固然查不出来了,子类重写了目标类的全部方法,固然在这些重写的方法中,不只实现了目标类的功能,还在这些功能以前,实现了一些其余的(写日志,安全检查,事物等)。
此次的对比就是,儿子先从爸爸那把本事都学会了,全部人都找儿子办事情,可是儿子每次办和爸爸一样的事以前,都要收点小礼物(写日志),而后才去办真正的事。固然爸爸是不知道儿子这么干的了。这里就有件事情要说,某些本事是爸爸独有的(final的),儿子学不了,学不了就办不了这件事,办不了这个事情,天然就不能收人家礼了。
前一种兄弟模式,spring会使用JDK的java.lang.reflect.Proxy类,它容许Spring动态生成一个新类来实现必要的接口,织入通知,而且把对这些接口的任何调用都转发到目标类。
后一种父子模式,spring使用CGLIB库生成目标类的一个子类,在建立这个子类的时候,spring织入通知,而且把对这个子类的调用委托到目标类。
相比之下,仍是兄弟模式好些,他能更好的实现松耦合,尤为在今天都高喊着面向接口编程的状况下,父子模式只是在没有实现接口的时候,也能织入通知,应当作一种例外。
前几篇博客咱们说了JAVA的代理模式,从静态代理到动态代理,又到CGLIB代理。从静态代理到动态代理是一种进步,JDK的动态代理和CGLIB的代理,倒是各有优缺点,在使用过程当中,不是非要决出个胜负,根据不一样的情景,使用不一样的代理;也能够根据状况,二者结合使用,代码是咱们写出来的,咱们才是创造者,知其然,知其因此然,然可用之。
1、AOP
这篇博客,咱们说说java的AOP。之因此接着说AOP 是由于,我认为代理模式和AOP 本就是一家,AOP是一种很先进的思想,而这种思想的技术支撑是:动态代理。最初,我也没有发现他们的关系,后来走着走着,就从AOP学回到到动态代理了,发现,原来是AOP的实现机制之一就是有“动态代理”的支持。回归正题,咱们先说说什么是AOP?
AOP : Aspect Oriented Programming 面向切面编程。它是为解耦而生的。
解耦是程序员编码开发过程当中一直追求的境界。AOP在这方面给程序员带来的福音,在对业务类的隔离方面来讲,它绝对是作到了解耦,但毫不是完美的解耦,这里在接下来的博客中再作介绍,这篇博客的主题是理解AOP。AOP的具体思想是:定义一个切面,在切面的纵向定义处理方法,处理完成以后,回到横向业务流,找一个简单的业务为例来讲:
从图中看出,AOP对咱们的业务的纵向走势不会形成阻碍做用,因此所面向切面变成是对面向对象编程的一种补充。上图是简单的一个AOP横向逻辑切入业务逻辑纵向逻辑的一个直挂展现,有些人会问?为何要这样作?咱们有那么多的横切行的必要吗?如今咱们看看使用AOP能够帮助咱们避免那些问题?基本算是AOP的一个由来吧。
先来看第一个问题,aop解决了大量的代码重复。
我须要作一个日志的功能,即须要在每条线上都进行日志的处理,咱们是否是要这么写?
这样有不少条线中都包含了一段相同的代码,你怎么看?抽出来呗,做为公共的部分,被调用。
而后呢,到这里咱们尚未结束,为何这么说?
这样每一个方法都和这个公共的功能类有关联关系,这里只是咱们的抽出公共代码,解决了代码重复。咱们须要作的是“解耦”,将业务类和这个公共的功能类之间的耦合解开,在运行的时候动态的给切入到每一个运行的业务类中,那么怎么实现呢?
AOP实现业务和切入类的解耦。
AOP是如何实现的呢?借助动态代理。前几篇博客咱们说了动态代理,动态代理的一个最大特征就是能够延迟对象的加载,即在运行期再肯定调用者和被调用者的关系。AOP也就是利用了动态的这个特征来实现的解耦。具体我就很少说了,详情看代码。
AOP的主要应用
直接上图吧。
这张图也形象的展现了,软件的纵向业务发展,和软件的横向AOP切入的原理。我以为之后,咱们的开发能够更多的抽取这样的切面,让每一个系统的开发只专一于核心的业务,而不考虑这样,那样的共性问题。