(七)springboot加入AOP及初探

相关概念
aspect:切面,横切多层面的关注点的模块化
Joinpoint:连接点.程序执行期间的一个点,连接点总是代表一个方法的执行.
advice:通知, 在特定连接点处采取的行动.包括before,after,around等.
Pointcut:切入点.定义一个类似正则的表达式,与通知相关联.
简单例子
项目为springboot项目,JDK1.8,工具idea
代码上的注释,是在测试包含所有通知下测的结果,实际开发中是不会都用到的,最多的是around,功能比较强大.
首先添加依赖:
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
        <version>1.5.9.RELEASE</version>
    </dependency>

定义一个切面:
@Aspect    //声明切面
@Component  //交给spring管理
public class AspectHandler{
    /**
     * 用作切入点的方法,必须具有void返回类型
     * 凡是符合这个表达式的,都将会被执行通知
     * 也可以写在每一个通知里;如下:
     * @Before("execution(* com.surd.aopdemo.service..*.*(..))")
     */
    @Pointcut("execution(* com.surd.aopdemo.service..*.*(..))")
    private void pointcut() {}

     /**
      * 前置增强
      * 当没有around时,先执行before, 走after,遇到异常,然后afterthrowing,
      * 如果没有异常走afterreturning,在这里可以看到返回值
      */
     @Before("pointcut()")  //通知类型的一种,所关联的切入点表达式是pointcut方法
     public void doBeforeTest(JoinPoint point) {
         //想要执行的代码
        System.out.println("execute before method===" + point);
     }

    /**
     * 后置增强,方法退出时执行
     */
    @AfterReturning(returning = "ret",pointcut = "pointcut()")
    public void doAfterReturning(JoinPoint point,Object ret) {
        System.out.println("execute AfterReturning" + point + ":return value:" + ret);
        ret = "return value";
    }

   /**
    * 最终(final)增强,不管方法退出还是抛出异常都会执行
    */
    @After("pointcut()")
    public void  doAfter(JoinPoint point) {
        // 想要执行的代码
         System.out.println("execute after method" + point);
    }

   /**
    * 异常增强
    */
  @AfterThrowing(throwing = "ex",pointcut = "pointcut()")
  public void doAfterThrowing(JoinPoint point,Exception ex) {
    System.out.println("execute afterThrowing" + point +"---exception:" + ex);
  }

  /**
   * 环绕增强
   * 当around存在的时候,首先执行.再before,如果遇到异常,执行after方法,走afterthrowing结束.
   * 当around存在的时候,首先执行.再before,再执行after方法,没有异常然后AfterReturning方法
   */
   @Around("pointcut()")
   public Object doAround(ProceedingJoinPoint point) throws Throwable {
      System.out.println("around before start");
      TODO:执行目标方法前执行的代码
      Object[] args = point.getArgs();
      args[0] = "gulang";
      Object ret = point.proceed(args); // 回调目标方法
      TODO:执行目标方法后执行的代码
      System.out.println("around end");
      System.out.println("execute around method" + point);
      return ret;
    }
}

Service层代码:  当某一个类的方法符合pointcut表达式,就是在idea左边显示相对应的小图标

这里写图片描述

controller层就不贴出来了,直接调用就好;
在没个通知打上断点,可以观察执行的顺序以及参数值,也就是连接点的内容
这里写图片描述

其中包含了代理对象,目标对象,方法,参数,动态匹配到的方法等等都可以查看到.
一个简单的例子就完成了. 这样我们就可以使用它去记录日志,缓存等等.

浅析1:
(一)AOP代理实现有两种方法:
    1:默认使用标准JDK动态代理,这使得任何接口都可以被代理.
    2:也可以使用CGLIB代理,如果业务对象没有实现接口,就默认CGLIB,也可以强制使用.但是有一些问题需要考虑(下图给出官方描述):

这里写图片描述
1️⃣就是说不能用final修饰类,否则无法覆盖;
2️⃣在spring3.2中,不再需要将cglib添加到项目类路径,spring核心jar已经包含,这就意味着,基于CGLIB代理支持,工作方式相同,JDK动态代理总是有的.
3️⃣代理构造器会被调用两次.

(二)@Aspect注解对于类路径中的自动检测是不够的,所以还需要添加单独的@Component 

(三)切入点表达式和切入点签名:
 @Pointcut("execution(* com.surd.aopdemo.service..*.*(..))") //切入点表达式
 private void pointcut() {}  //切入点签名

 (四)支持的切入点指示符:
     execute: 常用, 方法匹配
     @annotation: 注解匹配;(限制匹配连接点的地方有给定的注解)
     within:限制匹配某些类型内的连接点(只需执行在匹配类型中声明的方法)
     @within:在具有给定注解的类型内部限制匹配连接点(执行使用给定注解的类型中声明的方法)
     args: 限制匹配连接点,其中参数是给定类型的实例
     @args:限制匹配连接点,实际参数的运行时类型有给定类型的注解

更详细的描述,还有很多指示符,请参考官方文档:https://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/aop.html#aop-introduction

切入点表达式:
切入点表达式可以使用&&, ||,!进行组合.也可以通过名称来引用切入点表达式.以下代码摘自官网:
//匹配任何公共方法
 @Pointcut(“execution(public * *(..))”)
 private void anyPublicOperation(){}
//匹配交易模块中的方法
 @Pointcut( “within(com.xyz.someapp.trading。*)”)
 private void inTrading(){}
//匹配交易模块中额任何公共方法
 @Pointcut(“anyPublicOperation()&& inTrading()”)
 private void tradingOperation(){} 

表达式格式:execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)
throws-pattern?)
() : 表示匹配一个不带参数的方法;
(..): 表示匹配任意数量的参数(0个或者多个);
(*): 表示任意类型的一个参数的方法;
(*,String):表示匹配一个方法采用两个参数,第一个是任意类型,第二个必须是String类型;
* : 匹配任意字符,但只能匹配一个元素
.. : 匹配任意字符,可以匹配任意多个元素,表示类时,与*联合使用
+ : 必须跟在类名后面,表示类本身和集成或者扩展指定类的所有类

JoinPoint:

该接口提供了许多有用的方法如:

getArgs(): 返回方法参数
getThis(): 返回代理对象
getTarget(): 返回目标对象
getSignature(): 返回正在被通知的方法的描述
……

暂时写到这里;
小结:

1️⃣: spring aop是基于代理的(JDK动态代理和CGLIB);
2️⃣: 开发中只需要专注于业务功能,像日志这一类功能可以提取出来使用此类方法处理;
3️⃣: 根据应用中实际情况来定义粗粒度,细粒度的切入点,处理不同的需求;
更多详情参考spring aop: https://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/aop.html#aop-introduction

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值