什么是Spring 的AOP 首先需要理解代理两种模式JDK和CGLIB,
代理对象proxy拥有目标对象的所有方法,因为实现了共同的接口或者是目标对象的子类
生产一个代理类需要有一个类作为目标对象(target),在JVM运行生产代理对象(proxy)的时候可以调用目标对象的方法在动态的添加一段代码,
这个代码位置就可以有选择(advice),
我们可能只是在目标对象的几个方法需要动态加代码,所有需要一个标识(adivsor)
1.
Spring实现AOP(Aspect Oriented Programming)是依赖JDK动态代理和CGLIB代理(不同情况spring会自己选择一种方式)。JDK动态代理和CGLIB代理的对比:
JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理。
CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的。
所以spring会有以下俩种选择动态代理实现方式的情况:
*如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
*如果目标对象没有实现了接口,spring会使用CGLIB的库来实现代理
spring会自动在JDK动态代理和CGLIB之间自动选择;
2.
认识AOP中的一些基本概念,然后在一个一个的例子中,不断的加强对这些概念的理解,同时要能自己表述出每个概念的含义AOP 面向切面编程
*aspect 切面/切面类 ---->需要动态添加的代码
joinPoint 连接点
在spring的aop中只有 类中的方法 可以做连接点,每一个方法都可以是一个连接点.
---->在哪个方法添加(注入目标对象)
*pointCut 切入点
一组连接点的集合 - --->在哪些方法添加(注入目标对象)
advice 通知/拦截器
用来控制切面类将来到底是织入到切入点的前面、后面或者是抛异常的时候。
---->说明在目标对象所有方法的位置通知 (注入切面
*adivsor 增强器
用来筛选类中的哪些方法是我们的连接点(哪些方法需要被拦截).
---->作用是筛选要代理的目标对象方法(注入advice通知/切面和注入切入点一个patterns的方法名集合)
target 目标对象
proxy 代理对象
wave 织入
前置通知(Before advice):
在某连接点(join point)之前执行的通知
返回后通知(After returning advice):
在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。
抛出异常后通知(After throwing advice):
在方法抛出异常退出时执行的通知。
后通知(After (finally) advice):
当某连接点退出的时候执行的通知
环绕通知(Around Advice):
包围一个连接点(join point)的通知,例如事务的处理,就需要这样的通知,因为事务需要在方法前开启,在方法后提交
3.
aop:config标签使用aop的专用标签来完成相关的配置.
其中主要表现是使用AspectJ的expression的操作:
execution(modifiers-pattern ret-type-pattern declaring-type-pattern name-pattern(param-pattern) throws-pattern)除了返回类型模式,名字模式和参数模式以外,所有的部分都是可选的。 返回类型模式决定了方法的返回类型必须依次匹配一个连接点。 你会使用的最频繁的返回类型模式是 *,它代表了匹配任意的返回类型。 一个全称限定的类型名将只会匹配返回给定类型的方法。名字模式匹配的是方法名。 你可以使用 * 通配符作为所有或者部分命名模式。 参数模式稍微有点复杂:() 匹配了一个不接受任何参数的方法, 而 (..) 匹配了一个接受任意数量参数的方法(零或者更多)。 模式 (*) 匹配了一个接受一个任何类型的参数的方法。 模式 (*,String) 匹配了一个接受两个参数的方法,第一个可以是任意类型,第二个则必须是String类型
下面给出一些常见切入点表达式的例子。
1)任意包下的任意类中的公共方法的执行:
execution(public * *(..))
2)任何一个以“set”开始的方法的执行:
execution(* set*(..))
3)AccountService 接口的任意方法的执行:
execution(* com.gress.service.AccountService.*(..))
4)定义在service包里的任意方法的执行: 类 + 方法
execution(* com.gress.service.*.*(..))
5)定义在service包或者子包里的任意方法的执行:
execution(* com.gress.service..*.*(..))
6)在service包里的任意连接点(在Spring AOP中只是方法执行)
within(com.xyz.service.*)
7)在service包或者子包里的任意连接点(在Spring AOP中只是方法执行) :
within(com.xyz.service..*)
注意:1.从spring容器中拿代理对象的时候也是要用目标对象的名字来拿。
2.没有实现任何接口的目标对象也能产生代理对象。