AOP的基础知识总结(jdk动态代理/cglib动态代理)

AOP的基础知识总结(jdk动态代理/cglib动态代理)

知识总结

aop切面编程

切面:

  切面包含了通知和切点,通知和切点共同定义了切面是什么,在何时,何处执行切面逻辑。

切点:

  如果说通知定义了在何时执行通知,那么切点就定义了在何处执行通知。所以切点的作用就是
      通过匹配规则查找合适的连接点(Joinpoint),AOP 会在这些连接点上织入通知。

通知:

   Spring 中对应了 5 种不同类型的通知:
      · 前置通知(Before):在目标方法执行前,执行通知
      · 后置通知(After):在目标方法执行后,执行通知,此时不关系目标方法返回的结果是什么
      · 返回通知(After-returning):在目标方法执行后,执行通知
      · 异常通知(After-throwing):在目标方法抛出异常后执行通知
      · 环绕通知(Around): 目标方法被通知包裹,通知在目标方法执行前和执行后都被会调用

动态代理:

Spring在选择用JDK还是CGLiB的依据:

  (1)当Bean实现接口时,Spring就会用JDK的动态代理(就比如userServiceImpl实现了IUserService)
  (2)当Bean没有实现接口时,Spring使用CGlib是实现(就比如userServiceImpl没有实现IUserService)
  (3)可以强制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)

CGlib比JDK快?

(1)使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
(2)在对JDK动态代理与CGlib动态代理的代码实验中看,1W次执行下,JDK7及8的动态代理性能比CGlib要好20%左右。

JDK动态代理和CGLIB字节码生成的区别?

 (1)JDK动态代理只能对实现了接口的类生成代理,而不能针对类
 (2)CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
   因为是继承,所以该类或方法最好不要声明成final

而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

  1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 
  2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP 
  3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

Spring的aop的基本的使用:

增加依赖包:

  jdk:不需要额外添加依赖
  cglib:
    org.springframework.spring-aop.5.0.8.RELEASE
    org.aspectj.aspectjweaver.1.8.13
    org.springframework.spring-aspects.5.0.8.RELEASE
    aopalliance.aopalliance.1.0

增加切面类类:

  ① 在类上使用 @Component 注解 把切面类加入到IOC容器中
  ② 在类上使用 @Aspect 注解 使之成为切面类

案例(可以只使用环绕通知/其他的前置后置通知之一):

  @Component
  @Aspect
  public class LoggingAspect {

      /**
       * 前置通知:目标方法执行之前执行以下方法体的内容
       * @param jp
       */
      @Before("execution(* com.qcc.beans.aop.*.*(..))")
      public void beforeMethod(JoinPoint jp){
          String methodName = jp.getSignature().getName();
          System.out.println("【前置通知】the method 【" + methodName + "】 begins with " + Arrays.asList(jp.getArgs()));
      }

      /**
       * 返回通知:目标方法正常执行完毕时执行以下代码
       * @param jp
       * @param result
       */
      @AfterReturning(value="execution(* com.qcc.beans.aop.*.*(..))",returning="result")
      public void afterReturningMethod(JoinPoint jp, Object result){
          String methodName = jp.getSignature().getName();
          System.out.println("【返回通知】the method 【" + methodName + "】 ends with 【" + result + "】");
      }

      /**
       * 后置通知:目标方法执行之后执行以下方法体的内容,不管是否发生异常。
       * @param jp
       */
      @After("execution(* com.qcc.beans.aop.*.*(..))")
      public void afterMethod(JoinPoint jp){
          System.out.println("【后置通知】this is a afterMethod advice...");
      }

      /**
       * 异常通知:目标方法发生异常的时候执行以下代码
       */
      @AfterThrowing(value="execution(* com.qcc.beans.aop.*.*(..))",throwing="e")
      public void afterThorwingMethod(JoinPoint jp, NullPointerException e){
          String methodName = jp.getSignature().getName();
          System.out.println("【异常通知】the method 【" + methodName + "】 occurs exception: " + e);
      }

  //  /**
  //   * 环绕通知:目标方法执行前后分别执行一些代码,发生异常的时候执行另外一些代码
  //   * @return
  //   */
  //  @Around(value="execution(* com.qcc.beans.aop.*.*(..))")
  //  public Object aroundMethod(ProceedingJoinPoint jp){
  //      String methodName = jp.getSignature().getName();
  //      Object result = null;
  //      try {
  //          System.out.println("【环绕通知中的--->前置通知】:the method 【" + methodName + "】 begins with " + Arrays.asList(jp.getArgs()));
  //          //执行目标方法
  //          result = jp.proceed();
  //          System.out.println("【环绕通知中的--->返回通知】:the method 【" + methodName + "】 ends with " + result);
  //      } catch (Throwable e) {
  //          System.out.println("【环绕通知中的--->异常通知】:the method 【" + methodName + "】 occurs exception " + e);
  //      }
  //
  //      System.out.println("【环绕通知中的--->后置通知】:-----------------end.----------------------");
  //      return result;
  //  }
  }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值