Spring的AOP的注解配置方式

注意,AOP的实现原理没什么特别的,就是动态代理!
 

AOP简介 

AOP(Aspect-Oriented Programming, 面向切面编程 ): 是一种新的方法论 , 是对传统 OOP(Object-Oriented Programming, 面向对象编程 ) 的补充 .
AOP 的主要编程对象是 切面 (aspect), 切面模块化横切关注点 .
在应用 AOP 编程时 , 仍然 需要 定义 公共功能 , 但可以明确的定义这个功能在哪里 , 以什么方式应用 , 并且不必修改受影响的类 . 这样一来 横切关注点就被模块化到特殊的对象 ( 切面 ) .
AOP 的好处 :
每个事物逻辑位于一个位置 , 代码不分散 , 便于维护和升级
业务模块更简洁 , 只包含核心业务代码 .
 

示意图:

 

 AOP 术语

切面 (Aspect):  横切关注点 ( 跨越应用程序多个模块的功能 ) 被模块化的特殊对象
通知 (Advice):  切面必须要完成的工作
目标 (Target): 被通知的对象
代理 (Proxy): 向目标对象应用通知之后创建的对象
连接点( J oinpoint ): 程序 执行的某个特定位置 :如类某个方法调用前、调用后、方法抛出异常后等 连接点 由两个信息确定:方法表示的程序执行点;相对点表示的方位 。例如 ArithmethicCalculator#add () 方法执行 前的连接点,执行点为 ArithmethicCalculator#add () ; 方位为该方法执行前的 位置
切点( pointcut ): 每个 类都拥有多个连接点 :例如 ArithmethicCalculator 的所有方法实际上都是连接点,即 连接点是程序类中 客观存在 的事务 AOP 通过切点定位到特定的连接点 。类比 :连接点相当于数据库中的记录,切点相当于查询条件 。切点和连接点不是一对一的关系,一个切点匹配多个 连接点, 切点通过 org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的 查询条件

示意图: 

 

Spring 中启用 AspectJ 注解支持 

要在 Spring 应用中使用 AspectJ 注解 , 必须在 classpath 下包含 AspectJ 类库 : aopalliance.jar aspectj.weaver.jar spring-aspects.jar
aop Schema 添加到 <beans> 根元素中 .
Spring IOC 容器中启用 AspectJ 注解支持 , 只要 Bean 配置文件中定义一个空的 XML 元素 < aop:aspectj-autoproxy >
Spring IOC 容器侦测到 Bean 配置文件中的 < aop:aspectj-autoproxy > 元素时 , 会自动为与 AspectJ 切面匹配的 Bean 创建代理 .

 AspectJ 注解声明切面

要在 Spring 中声明 AspectJ 切面 , 只需要在 IOC 容器中将切面声明为 Bean 实例 . 当在 Spring IOC 容器中初始化 AspectJ 切面之后 , Spring IOC 容器就会为那些与 AspectJ 切面相匹配的 Bean 创建代理 .
AspectJ 注解中 , 切面只是一个带有 @Aspect 注解的 Java .
通知是标注有某种注解的简单的 Java 方法 .
AspectJ 支持 5 种类型的通知注解 :
@Before: 前置通知 , 在方法执行之前执行
@After: 后置通知 , 在方法执行之后执行
@ AfterRunning : 返回通知 , 在方法返回结果之后 执行
@ AfterThrowing : 异常通知 , 在方法抛出异常之后
@Around: 环绕通知 , 围绕着方法执行

前置通知 

前置通知 : 在方法执行之前执行的通知
前置通知使用 @Before 注解 , 并将切入点表达式的值作为注解值 .

 示意图:

 利用方法签名编写 AspectJ 切入点表达式

最典型的切入点表达式时根据方法的签名来匹配各种方法 :
execution * com.atguigu.spring.ArithmeticCalculator . * (..): 匹配 ArithmeticCalculator 中声明的所有方法 , 第一个 * 代表任意修饰符及任意返回值 . 第二个 * 代表任意方法 . .. 匹配任意数量的参数 . 若目标类与接口与该切面在同一个包中 , 可以省略包名 .
execution public * ArithmeticCalculator.*(..): 匹配 ArithmeticCalculator 接口的 所有公有方法 .
execution public double ArithmeticCalculator.*(..): 匹配 ArithmeticCalculator 返回 double 类型数值的方法
execution public double ArithmeticCalculator.*( double , ..): 匹配第一个参数为 double 类型的方法 , .. 匹配任意数量任意类型的参数
execution public double ArithmeticCalculator.*( double , double ): 匹配参数类型为 double, double 类型的方法 .

合并切入点表达式 

 •AspectJ , 切入点表达式可以通过操作符 &&, ||, ! 结合起来.

 

让通知访问当前连接点的细节 

可以在通知方法中声明一个类型为 JoinPoint 的参数. 然后就能访问链接细节. 如方法名称和参数值.

 在返回通知中访问连接点的返回值

在返回通知中 , 只要将 returning 属性添加到 @ AfterReturning 注解中 , 就可以访问连接点的返回值 . 该属性的值即为用来传入返回值的参数名称 .
必须在通知方法的签名中添加一个 同名参数 . 在运行时 , Spring AOP 会通过这个参数传递返回值 .
原始的 切点 表达式需要出现在 pointcut 属性中
•注意,其他的切面方法的参数也是类似,就是有这个参数的话,就必须在注解里面说明。JoinPoint除外。
 

 

后置通知(@After)

后置通知是在连接点完成之后执行的 , 即连接点返回结果或者抛出异常的时候 , 下面的后置通知记录了方法的终止 .
一个切面可以包括一个或者多个通知 .

返回通知 (@AfterReturning)

无论连接点是正常返回还是抛出异常 , 后置通知都会执行 . 如果只想在连接点返回的时候记录日志 , 应使用返回通知代替后置通知 .

异常通知 (@AfterThrowing )

只在连接点抛出异常时才执行异常通知
throwing 属性添加到 @ AfterThrowing 注解中 , 也可以访问连接点抛出的异常 . Throwable 是所有错误和异常类的超类 . 所以在异常通知方法可以捕获到任何错误和异常 .
如果只对某种特殊的异常类型感兴趣 , 可以将参数声明为其他异常的参数类型 . 然后通知就只在抛出这个类型及其子类的异常时才被执行 .

    例子:

 

环绕通知(@Around,这个是最特别的。很像动态代理)

环绕通知是所有通知类型中功能最为强大的 , 能够全面地控制连接点 . 甚至 可以控制是否执行连接点 .
对于环绕通知来说 , 连接点的参数类型必须是 ProceedingJoinPoint . 它是 JoinPoint 的子接口 , 允许控制何时执行 , 是否执行连接点 .
在环绕通知中需要明确调用 ProceedingJoinPoint proceed() 方法来执行被代理的方法 . 如果忘记这样做就会导致通知被执行了 , 但目标方法没有被执行 .
注意 : 环绕通知的方法需要返回目标方法执行之后的结果 , 即调用 joinPoint.proceed (); 的返回值 , 否则会出现空指针异常

 例子:

指定切面的优先级 

在同一个连接点上应用不止一个切面时 , 除非明确指定 , 否则它们的优先级是不确定的 .
切面的优先级可以通过实现 Ordered 接口或利用 @Order 注解指定 .
实现 Ordered 接口 , getOrder () 方法的返回值越小 , 优先级越高 .
若使用 @Order 注解 , 序号出现在注解中

 

重用切入点定义

在编写 AspectJ 切面时 , 可以直接在通知注解中书写切入点表达式 . 但同一个切点表达式可能会在多个通知中重复出现 .
AspectJ 切面中 , 可以 通过 @ Pointcut 注解将一个切入点声明成 简单的方法 . 切入点的方法体通常是空的 , 因为将切入点定义与应用程序逻辑混在一起是不合理的 .
切入点方法的访问控制符同时也控制着这个切入点的可见性 . 如果切入点要在多个切面中共用 , 最好将它们集中在一个公共的类中 . 在这种情况下 , 它们必须被声明为 public. 在引入这个切入点时 , 必须将类名也包括在内 . 如果类没有与这个切面放在同一个包中 , 还必须包含包名 . 
其他通知可以通过方法名称引入该切入点 .

 

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值