约定编程
先从约定编程入手。
举个例子:在操作数据库时,有很多步骤,如获取连接、注册驱动、执行SQL语句等等,其中最核心的是和业务有关的SQL语句,其他的都是重复性的工作。约定编程就是把最核心的操作单独拎起来,其他的重复步骤在流程中默认实现,以此少写些代码,方便了开发者。
Spring AOP
AOP(Aspect Oriented Programming),意为:面向切面编程。简单的说,就是把被封装的对象一刀“切开”,取出一些共同调用、但与具体业务无关公共行为,封装在一个可重用的模块中,这个模块就是“切面”。以此减少重复代码,降低耦合度,便于开发与维护。
AOP核心概念
切面(Aspect)
切面就是通用的业务逻辑代码,是通知和切入点的结合。
通知(Advice)
就是你想要的功能,也就是上面说的 安全,事物,日志等。
连接点(JoinPoint)
Sring中使用通知的地方,位置可以在方法的前、后,乃至抛出异常。
切入点(Pointcut)
不需要所有的连接点都织入通知,就需要切入点对连接点进行筛选。用正则表达式对连接点来筛选连接点,使不同的通知切入到不同的连接点。
引入(Introduction)
用通知的方式定义新方法属性到目标类中。
目标(Target)
引入中所提到的目标类,也就是要被通知的对象,是被代理的对象,是专注于业务本身的逻辑。
代理(Proxy)
代理对象是AOP创建的对象,是将通知应用到目标对象之后被动态创建的对象,可以简单理解代理对象的功能等同于目标对象的核心业务逻辑功能加上共有功能。代理对象对于使用者而言是透明的,是程序运行过程中的产物。
织入(Weaving)
通过动态代理技术,为原有服务对象生成代理对象,然后将与切点定义piper的连接点拦截,并按照约定将各类通知直入约定的流程。
对AOP的理解(转载 )
源地址:http://www.verydemo.com/demo_c143_i20837.html
spring用代理类包裹切面,把他们织入到Spring管理的bean中。也就是说代理类伪装成目标类,它会截取对目标类中方法的调用,让调用者对目标类的调用都先变成调用伪装类,伪装类中就先执行了切面,再把调用转发给真正的目标bean。
现在可以自己想一想,怎么搞出来这个伪装类,才不会被调用者发现(过JVM的检查,JAVA是强类型检查,哪里都要检查类型)。
1.实现和目标类相同的接口,我也实现和你一样的接口,反正上层都是接口级别的调用,这样我就伪装成了和目标类一样的类(实现了同一接口,咱是兄弟了),也就逃过了类型检查,到java运行期的时候,利用多态的后期绑定(所以spring采用运行时),伪装类(代理类)就变成了接口的真正实现,而他里面包裹了真实的那个目标类,最后实现具体功能的还是目标类,只不过伪装类在之前干了点事情(写日志,安全检查,事物等)。
这就好比,一个人让你办件事,每次这个时候,你弟弟就会先出来,当然他分不出来了,以为是你,你这个弟弟虽然办不了这事,但是他知道你能办,所以就答应下来了,并且收了点礼物(写日志),收完礼物了,给把事给人家办了啊,所以你弟弟又找你这个哥哥来了,最后把这是办了的还是你自己。但是你自己并不知道你弟弟已经收礼物了,你只是专心把这件事情做好。
顺着这个思路想,要是本身这个类就没实现一个接口呢,你怎么伪装我,我就压根没有机会让你搞出这个双胞胎的弟弟,那么就用第2种代理方式,创建一个目标类的子类,生个儿子,让儿子伪装我
2.生成子类调用,这次用子类来做为伪装类,当然这样也能逃过JVM的强类型检查,我继承的吗,当然查不出来了,子类重写了目标类的所有方法,当然在这些重写的方法中,不仅实现了目标类的功能,还在这些功能之前,实现了一些其他的(写日志,安全检查,事物等)。
这次的对比就是,儿子先从爸爸那把本事都学会了,所有人都找儿子办事情,但是儿子每次办和爸爸同样的事之前,都要收点小礼物(写日志),然后才去办真正的事。当然爸爸是不知道儿子这么干的了。这里就有件事情要说,某些本事是爸爸独有的(final的),儿子学不了,学不了就办不了这件事,办不了这个事情,自然就不能收人家礼了。
前一种兄弟模式,spring会使用JDK的java.lang.reflect.Proxy类,它允许Spring动态生成一个新类来实现必要的接口,织入通知,并且把对这些接口的任何调用都转发到目标类。
后一种父子模式,spring使用CGLIB库生成目标类的一个子类,在创建这个子类的时候,spring织入通知,并且把对这个子类的调用委托到目标类。
相比之下,还是兄弟模式好些,他能更好的实现松耦合,尤其在今天都高喊着面向接口编程的情况下,父子模式只是在没有实现接口的时候,也能织入通知,应当做一种例外。