spring-Aop

概述

AOP的全称是Aspect Oriented Programming(面向切面编程)

OOP语言提供了类与类之间纵向的关系(继承、接口),而AOP补充了横向的关系(比如在不改变目标类中源代码的情况下给com.john.demo.dao包下所有类中以insert和update开头的方法添加事务管理)

SpringAOP和AspectJ的区别

AspectJ是一个专门主打面向切面编程的框架。 它是使用一种特殊的语言(扩展自Java语言)来编写切面代码,后缀是.aj格式,并且需要使用专门的编译器将其编译成jvm可以运行的class文件。

SpringAOP底层也是使用了AspectJ的方案,但是在上层做了很多封装层面的工作,可以让开发人员直接使用Java代码来编写切面。并且由于使用的是标准的Java语言,所以并不需要在额外安装一个专门的编译器。但是由于开发人员直接接触的是Spring AOP,那么凡是Spring中没有实现的那些AOP功能,我们就用不了了,这种情况下只能跟产品经理撕逼或者去学习原生的AspectJ。

AOP的术语

  • 切面(Aspect)

    简单来说,切面就是我们要往目标代码中插入进去的代码。

  • 连接点(Join Pointer)

    理论上所有可能会被切入的地方都可以称之为连接点

  • 切入点(Pointcut)

    选择某个连接点切入,将切面代码织入进去。这个连接点就叫做切入点。

  • 织入(Weaving)

    把切面代码糅合到目标代码中的过程就是织入。

  • 通知(Advice)

    通知决定了切面代码织入到目标代码中后,运行的时机(比如是在目标方法执行前,还是执行后)。

在Spring中使用AOP

基于XML方式使用

  1. 把aop的schema引入
   <beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:aop="http://www.springframework.org/schema/aop"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.springframework.org/schema/aop
     http://www.springframework.org/schema/aop/spring-aop.xsd">
  1. 创建一个切面类,并且以bean的方式配置到IOC容器中
    package com.lanou3g.spring;
    public class MyAspect {
    ​
     public void wakeup() {
     System.out.println("[前置通知]我刚学习SpringAOP睡着了,刚才谁打了我一下?");
     }
    ​
    ​
     public void goToBed() {
     System.out.println("[后置通知]SpringAOP太难了,一不小心又睡着了");
     }
    ​
    ​
     public void afterRetuing(Object message) {
     System.out.println("[后置返回通知]方法执行已经return了,方法返回值是:" + message);
     }
    ​
     public void afterThrowing(Throwable ex) {
     System.out.println("[后置异常通知]方法执行出现异常,异常原因:" + ex.getMessage());
     }
    ​
     /**
     * 环绕通知
     * 可以接受一个ProceedingJoinPoint参数
     *      通过此参数可以获取到被切入方法的所有信息
     *      还可以通过此参数来决定是否调用目标方法
     */
     public void aroundAdvice(ProceedingJoinPoint joinPoint) {
    ​
     // 连接点参数可以获取到被切入方法的所有信息
     // 这里演示了如何获取被切入方法的名称
     String targetMethodName = joinPoint.getSignature().getName();
     System.out.println("[环绕通知]被切入的方法名:" + targetMethodName);
    ​
     //
     System.out.println("[环绕通知]即将开始新的一天, 早起的鸟儿有虫吃!");
     try {
     joinPoint.proceed();
     } catch (Throwable throwable) {
     throwable.printStackTrace();
     }
     System.out.println("[环绕通知]这真是充实的一天, 早睡早起,方能养生!");
     }
    }
<bean id="myAspect" class="com.lanou3g.spring.MyAspect" />
  1. 使用aop:config标签配置aop(将切面、切入点、通知结合到一起)

    1. 定义切入点表达式

    2. aop:aspect

      1. 引用外部定义的切面bean

      2. 配置通知,引用切入点表达式

<aop:config>
  <!-- 切入点表示匹配com.lanou3g.spring包下的所有类中所有以oneDay开头的方法,方法的参数、返回值不限 -->
  <aop:pointcut id="myPointcut" expression="execution(* com.lanou3g.spring..*.oneDay*(..))" />
  <aop:aspect ref="myAspect">
  <!-- 无论是否出现异常,只要被切入的方法开始运行,都会触发此通知 -->
  <aop:before method="wakeup" pointcut-ref="beforeOneDay" />
  <!-- 无论是否出现异常,只要被切入的方法运行结束,都会触发此通知 -->
  <aop:after method="goToBed" pointcut-ref="beforeOneDay" />
  <!--
  可以最大限度的对被切入方法附加功能,在方法执行前、后都可以通知(无论是否出现异常)
  ,还可以获取到被切入方法的所有信息,包括是否调用被切入的方法
  -->
  <aop:around method="aroundAdvice" pointcut-ref="beforeOneDay" />
  <!-- 被切入的方法正常返回值以后,会触发此通知 -->
  <aop:after-returning method="afterRetuing" pointcut-ref="beforeOneDay" returning="message" />
  <!-- 被切入的方法抛出异常以后,会触发此通知,并且不会触发after-returning -->
  <aop:after-throwing method="afterThrowing" pointcut-ref="beforeOneDay" throwing="ex" />
  </aop:aspect>
 </aop:config>

基于注解方式使用

  1. 开启AOP注解支持

    方式一:注解的方式

  @Configuration
    @EnableAspectJAutoProxy
    public class AppConfig {
    ​
    }
方式二:xml中开启
   <aop:aspectj-autoproxy/></pre>
2.  定义切面类
   /**
     * 该切面用来插入起床的逻辑
     */
    @Aspect
    @Component  //@Aspect注解没有将bean交给ioc容器管理的功能
    public class MyAspect {
    ​
     @Before("com.lanou3g.spring.aop.MyPointcut.allOneDayMehtod()")
     public void wakeup() {
     System.out.println("[前置通知]我刚学习SpringAOP睡着了,刚才谁打了我一下?");
     }
    ​
     @After("com.lanou3g.spring.aop.MyPointcut.allOneDayMehtod()")
     public void goToBed() {
     System.out.println("[后置通知]SpringAOP太难了,一不小心又睡着了");
     }
    ​
     @AfterReturning(value = "com.lanou3g.spring.aop.MyPointcut.allOneDayMehtod()", returning = "message")
     public void afterRetuing(Object message) {
     System.out.println("[后置返回通知]方法执行已经return了,方法返回值是:" + message);
     }
    ​
     @AfterThrowing(value = "com.lanou3g.spring.aop.MyPointcut.allOneDayMehtod()", throwing = "ex")
     public void afterThrowing(Throwable ex) {
     System.out.println("[后置异常通知]方法执行出现异常,异常原因:" + ex.getMessage());
     }
    ​
     /**
     * 环绕通知
     * 可以接受一个ProceedingJoinPoint参数
     *      通过此参数可以获取到被切入方法的所有信息
     *      还可以通过此参数来决定是否调用目标方法
     */
    //    @Around("com.lanou3g.spring.aop.MyPointcut.allOneDayMehtod()")
     public Object aroundAdvice(ProceedingJoinPoint joinPoint) {
    ​
     // 连接点参数可以获取到被切入方法的所有信息
     // 这里演示了如何获取被切入方法的名称
     String targetMethodName = joinPoint.getSignature().getName();
     System.out.println("[环绕通知]被切入的方法名:" + targetMethodName);
    ​
     //
     System.out.println("[环绕通知]即将开始新的一天, 早起的鸟儿有虫吃!");
     Object ret = null;
     try {
     ret = joinPoint.proceed();
     } catch (Throwable throwable) {
     throwable.printStackTrace();
     }
     System.out.println("[环绕通知]这真是充实的一天, 早睡早起,方能养生!");
     return ret;
     }
    }
> 注意:@Aspect注解没有将bean交给ioc容器管理的功能,我们需要额外添加一个@Component注解

3.  定义切入点

官方建议我们将所有的切入点统一定义到一个地方管理,在配置通知时通过引入的方式来使用。方便后期维护(一处修改,处处生效)

   @Component
    public class MyPointcut {
     // 通过@Pointcut注解定义一个切入点
     @Pointcut("execution(* oneDay(..))")
     public void allOneDayMehtod() {}
    }
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring AOP解决问题 相比较于面向过程程序设计(POP),面向对象程序设计(OOP)更加注重封装与隔离,以...
    桴海阅读 224评论 0 0
  • Spring的AOPAOP的基本概念基于注解的“零配置”方式定义切面Bean定义Before增强处理定义After...
    渐丶忘阅读 1,620评论 0 0
  • 因为工作需求,自己去了解一下aop并做下的记录,当然大部分都是参考他人博客以及官方文档。 目录 [关于 AOP](...
    forip阅读 2,292评论 1 20
  • 前言 只有光头才能变强 上一篇已经讲解了Spring IOC知识点一网打尽!,这篇主要是讲解Spring的AOP模...
    Java3y阅读 6,905评论 8 181
  • [TOC] 概述 在软件开发中,散布于应用中多处的功能被称为横切关注点(cross-cutting concern...
    0x70e8阅读 625评论 0 0