6. Spring AOP 应用 AOP本质:在不改变原有业务逻辑的情况下增强横切逻辑,横切逻辑代码往往是权限校验代码、日志代码、事务控制代码、性能监控代码。
6.1 相关术语 1. 业务主线 在讲解AOP术语之前,我们先来看一下下面这两张图,它们就是第三部分案例需求的扩展(针对这些扩 展的需求,只进行分析,在此基础上去进一步回顾AOP,不进行实现)
上图描述的就是未采用AOP思想设计的程序,当我们红色框中圈定的方法时,会带来大量的重复劳动。 程序中充斥着大量的重复代码,使我们程序的独立性很差。而下图中是采用了AOP思想设计的程序,它把红框部分的代码抽取出来的同时,运用动态代理技术,在运行期对需要使用的业务逻辑方法进行增强。
2. AOP术语 
连接点 :方法开始时、结束时、正常运行完毕时、方法异常时等这些特殊的时机点,我们称之为连接点,项目中每个方法都有连接点,连接点是一种候选点切入点 :指定AOP思想想要影响的具体方法是哪些,描述感兴趣的方法Advice增强 :第一个层次:指的是横切逻辑 第二个层次:方位点(在某一些连接点上加入横切逻辑,那么这些连接点就叫做方位点,描述的是具体的特殊时机) Aspect切面 :切面概念是对上述概念的一个综合Aspect切面 = 切入点+增强 = 切入点(锁定方法) + 方位点(锁定方法中的特殊时机) + 横切逻辑 众多的概念,目的就是为了锁定要在哪个地方插入什么横切逻辑代码。 
6.2 代理选择 Spring 实现AOP思想使用的是动态代理技术 默认情况下,Spring会根据被代理对象是否实现接口来选择使用JDK还是CGLIB。当被代理对象没有实现任何接口时,Spring会选择CGLIB。当被代理对象实现了接口,Spring会选择JDK官方的代理技术,不过 我们可以通过配置的方式,让Spring强制使用CGLIB。
6.3 AOP的配置方式 在Spring的AOP配置中,也和IoC配置一样,支持3类配置方式。
第一类:使用XML配置 第二类:使用XML+注解组合配置 第三类:使用纯注解配置 6.4 AOP实现 需求:横切逻辑代码是打印日志,希望把打印日志的逻辑织入到目标方法的特定位置(service层transfer方法)
1. xml模式 引入依赖 <dependency >     <groupId > org.springframework</groupId >      <artifactId > spring-aop</artifactId >      <version > 5.1.12.RELEASE</version >  </dependency > <dependency >     <groupId > org.aspectj</groupId >      <artifactId > aspectjweaver</artifactId >      <version > 1.9.4</version >  </dependency > 
核心配置          <bean  id ="logUtils"  class ="com.lagou.edu.utils.LogUtils" > </bean >                <aop:config >          <aop:aspect  id ="logAspect"  ref ="logUtils" >                                        <aop:pointcut  id ="pt1"  expression ="execution(* com.lagou.edu.service.impl.TransferServiceImpl.*(..))" />                                        <aop:before  method ="beforeMethod"  pointcut-ref ="pt1" />                                                     <aop:around  method ="arroundMethod"  pointcut-ref ="pt1" />          </aop:aspect >      </aop:config >  
**切入点表达式 **
上述配置实现了对 TransferServiceImpl 的 updateAccountByCardNo 方法进行增强,在其执行之前,输出了记录日志的语句。这里面,我们接触了一个比较陌生的名称:切入点表达式,它是做什么的呢?我们往下看。
概念及作用 切入点表达式,也称之为AspectJ切入点表达式,指的是遵循特定语法结构的字符串,其作用是用于对符合语法格式的连接点进行增强。它是AspectJ表达式的一部分。 关于AspectJ 切入点表达式使用示例  全限定方法名 访问修饰符 返回值 包名.包名.包名.类名.方法名(参数列表) 全匹配方式: public  void  com.lagou.service.impl.TransferServiceImpl.updateAccountByCardNo(com.lagou.pojo.Account)访问修饰符可以省略 void  com.lagou.service.impl.TransferServiceImpl.updateAccountByCardNo(com.lagou.pojo.Account)返回值可以使用*,表示任意返回值 * com.lagou.service.impl.TransferServiceImpl.updateAccountByCardNo(com.lagou.pojo.Account) 包名可以使用.表示任意包,但是有几级包,必须写几个* * *.*.*.*.TransferServiceImpl.updateAccountByCardNo(com.lagou.pojo.Account) 包名可以使用..表示当前包及其子包 * *..*.TransferServiceImpl.updateAccountByCardNo(com.lagou.pojo.Account) 类名和方法名,都可以使用.表示任意类,任意方法 * *..*.*(com.lagou.pojo.Account)  参数列表,可以使用具体类型 基本类型直接写类型名称 : int   引用类型必须写全限定类名:java.lang.String 参数列表可以使用*,表示任意参数类型,但是必须有参数  * *..*.*(*) 参数列表可以使用..,表示有无参数均可。有参数可以是任意类型  * *..*.*(..) 全通配方式: * *..*.*(..) 
2. xml + 注解 使用注解配置切面:
@Component @Aspect public  class  LogUtils      @Pointcut("execution(* com.lagou.edu.service.impl.TransferServiceImpl.*(..))")      public  void  pt1 ()      }          @Before("pt1()")      public  void  beforeMethod (JoinPoint joinPoint)           Object[] args = joinPoint.getArgs();         for  (int  i = 0 ; i < args.length; i++) {             Object arg = args[i];             System.out.println(arg);         }         System.out.println("业务逻辑开始执行之前执行......." );     }          @After("pt1()")      public  void  afterMethod ()           System.out.println("业务逻辑结束时执行,无论异常与否都执行......." );     }          @AfterThrowing("pt1()")      public  void  exceptionMethod ()           System.out.println("异常时执行......." );     }          @AfterReturning(value = "pt1()", returning = "retVal")      public  void  successMethod (Object retVal)           System.out.println("业务逻辑正常时执行......." );     }               public  Object arroundMethod (ProceedingJoinPoint proceedingJoinPoint)  throws  Throwable          System.out.println("环绕通知中的beforemethod...." );         Object result = null ;         try {                                   }catch (Exception e) {             System.out.println("环绕通知中的exceptionmethod...." );         }finally  {             System.out.println("环绕通知中的after method...." );         }         return  result;     } } 
开启aop注解驱动:
3. 纯注解模式 只需要在xml + 注解模式的基础下,定义一个配置类或者在已有配置类的基础上加上一个注解@EnableAspectJAutoProxy即可。基础下,定义一个配置类或者在已有配置类的基础上加上一个注解@EnableAspectJAutoProxy即可。