一般来讲,谈到Spring的特性,绕不过去的就是DI(依赖注入)和AOP(切面),在将bean的系列中,说了DI的多种使用姿势;接下来看一下AOP的玩法
  
  <!-- more -->
  
  I. 背景知识
  
  在实际使用之前有必要了解一下什么是AOP,以及AOP的几个基本概念
  
  1. advice
  
  before: 在方法执行之前被调用
  
  after: 在方法执行之后调用
  
  after returning: 方法执行成功之后
  
  after throwing: 方法抛出异常之后
  
  around: 环绕,自己在内部决定方法的执行时机,因此可以在之前之后做一些业务逻辑
  
  2. join point
  
  连接点,比如方法调用,方法执行,字段设置/获取、异常处理执行、类初始化、甚至是 for 循环中的某个点
  
  但 Spring AOP 目前仅支持方法执行 (method execution)
  
  简单来说,Spring AOP中,PointCut就是那个被拦截的方法
  
  3. pointcut
  
  切点,用来描述满足什么规则的方法会被拦截
  
  正则表达式 : @Before("execution(public * com.git.hui.demo.base.bean.*.*(..))")
  
  注解拦截方式 :@Around("@annotation(parameterCheck)")
  
  4. aspect
  
  切面是切点和通知的结合。通知和切点共同定义了关于切面的全部内容,它是什么时候,在何时和何处完成功能
  
  5. introduction
  
  引入允许我们向现有的类添加新的方法或者属性
  
  6. weaving
  
  组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
  
  简单来讲就是生成一个代理类,在调用被拦截的方法时,实际上执行的是代理类,这个代理类内部执行切面逻辑
  
  II. 使用说明
  
  1. 基本配置
  
  首先是基本环境的搭建, 先贴上必要的xml配置, 使用aop需要引入包: spring-boot-starter-aop
  
  <parent>
  
  <groupId>org.springframework.boot</groupId>
  
  <artifactId>spring-boot-starter-parent</artifactId>
  
  <version>2.0.4.RELEASE</version>
  
  <relativePath/> <!-- lookup parent from repository -->
  
  </parent>
  
  <properties>
  
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  
  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  
  <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
  
  <java.version>1.8</java.version>
  
  </properties>
  
  <dependencies>
  
  <dependency>
  
  <groupId>org.springframework.boot</groupId>
  
  <artifactId>spring-boot-starter-aop</artifactId>
  
  </dependency>
  
  </dependencies>
  
  <build>
  
  <pluginManagement>
  
  <plugins>
  
  <plugin>
  
  <groupId>org.springframework.boot</groupId>
  
  <artifactId>spring-boot-maven-plugin</artifactId>
  
  </plugin>
  
  </plugins>
  
  </pluginManagement>
  
  </build>
  
  <repositories>
  
  <repository>
  
  <id>spring-milestones</id>
  
  <name>Spring Milestones</name>
  
  <url>https://repo.spring.io/milestone</url>
  
  <snapshots>
  
  <enabled>false</enabled>
  
  </snapshots>
  
  </repository>
  
  </repositories>
  
  2. 代码准备
  
  首先创建一个被拦截的bean: com.git.hui.boot.aop.demo.DemoBean,如下
  
  @Component
  
  public class DemoBean {
  
  /**
  
  * 返回随机的字符串
  
  *
  
  * @param time
  
  * @return
  
  */
  
  public String randUUID(long time) {
  
  try {
  
  System.out.println("in randUUID before process!");
  
  return UUID.randomUUID() + "|" + time;
  
  } finally {
  
  System.out.println("in randUUID finally!");
  
  }
  
  }
  
  }
  
  接着在启动类中,执行
  
  @SpringBootApplication
  
  public class Application {
  
  public Application(DemoBean demoBean) {
  
  String ans = demoBean.randUUID(System.currentTimeMillis());
  
  System.out.println("----- ans: " + ans + "---------");
  
  }
  
  public static void main(String[] args) {
  
  SpringApplication.run(Application.class);
  
  }
  
  }
  
  3. AOP使用
  
  在实际使用之前,需要创建一个切面,用@Aspect声明,其次切面也需要作为bean托付给Spring容器管理
  
  @Aspect
  
  @Component
  
  public class AnoAspcet {
  
  }
  
  a. before
  
  在方法调用之前,需要执行一些操作,这个时候可以使用 @Before 注解来声明before advice
  
  一种可使用姿势如下,我们的切点直接在注解中进行定义,使用正则表达式的方式
  
  @Before("execution(public * com.git.hui.boot.aop.demo.*.*(*))")
  
  public void doBefore(JoinPoint joinPoint) {
  
  System.out.println("do in Aspect www.mcyulegw.com before method called! args: " + JSON.toJSONString(joinPoint.getArgs()));
  
  }
  
  b. after
  
  在方法调用完毕之后,再执行一些操作,这个时候after就可以派上用场,为了考虑切点的通用性,我们可以考虑声明一个切点,使用@Pointcut注解
  
  @Pointcut("execution(public * com.git.hui.boot.aop.demo.*.*(*))")
  
  public void point(www.yongshiyule178.com) {
  
  }
  
  使用pointcut的方式也比较简单,如下
  
  @After("point(www.dfgjpt.com)")
  
  public void doAfter(JoinPoint joinPoint) {
  
  System.out.println("do in Aspect www.yongshi123.cn after method called! args: " + JSON.toJSONString(joinPoint.getArgs()));
  
  }
  
  c. after returning
  
  在正常返回结果之后,再次执行,这个也挺有意思的,通常使用这个advice时,一般希望获取返回结果,那么应该怎么处理呢?
  
  org.aspectj.lang.annotation.AfterReturning#returning 指定返回结果对应参数name
  
  返回结果作为参数传入,要求类型一致,否则不生效
  
  /**
  
  * 执行完毕之后,通过 args指定参数;通过 returning 指定返回的结果,要求返回值类型匹配
  
  *
  
  * @param time
  
  * @param result
  
  */
  
  @AfterReturning(value = "point(www.baohuayule.net/) && args(time)", returning = "result")
  
  public void doAfterReturning(www.michenggw.com long time, String result) {
  
  System.out.println("do in Aspect after method www.jiahuayulpt.com return! args: " + time + " ans: " + result);
  
  }
  
  d. around
  
  这个也比较常见,在方法执行前后干一些事情,比如常见的耗时统计,日志打印,安全控制等,很多都是基于around advice实现的
  
  使用这个advice需要注意的是传入参数类型为 ProceedingJoinPoint,需要在方法内部显示执行org.aspectj.lang.ProceedingJoinPoint#proceed()来表示调用方法
  
  @Around("point()")
  
  public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
  
  System.out.println("do in Aspect around ------ before");
  
  Object ans = joinPoint.proceed();
  
  System.out.println("do in Aspect around ------- over! ans: " + ans);
  
  return ans;
  
  }
  
  e. 输出
  
  执行之后输出如下
  
  do in Aspect around ------ before
  
  do in Aspect before method called! args: [1551433188205]
  
  in randUUID before process!
  
  in randUUID finally!
  
  do in Aspect around ------- over! ans: 6849544b-160e-464c-80bd-641f2651c6c1|1551433188205
  
  do in Aspect after method called! args: [1551433188205]
  
  do in Aspect after method return! args: 1551433188205 ans: 6849544b-160e-464c-80bd-641f2651c6c1|1551433188205
  
  ----- ans: 6849544b-160e-464c-80bd-641f2651c6c1|1551433188205---------
  
  从输出结果上,可以看到每个advice的使用范围,当然也带来了一些疑问
  
  可以存在多个同类型的advice,拦截同一个目标吗?(如两个around都拦截methodA方法,那么methodA方法被调用时,两个around advice是否都会执行)
  
  多个advice之间的优先级怎么定义?
  
  aop拦截的目标方法有没有限制(对非public的方法可以拦截么?)
  
  被拦截的方法中存在相互调用的时候,会怎样?(如methodA,methodB都可以被拦截,且methodA中调用了methodB,那么在执行methodA时,methodB的各种advice是否会被触发?)
  
  基于注解的aop方式可以怎样用
  
  以上这些问题留在下一篇进行介绍
  
  III. 其他
  
  0. 项目
  
  工程:https://www.dashuju2.cn github.com/liuyueyi/spring-boot-demo
  
  项目: https://www.yibaoyule1.com www.tianjuyuLe.cn github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/010-aop
  
  1. 一灰灰Blog
  
  一灰灰Blog个人博客 https://www.maituyul1.cn blog.hhui.top
  
  一灰灰Blog-Spring专题博客 http://www.wujirongyaoy.com spring.hhui.top
  
  一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
  
  2. 声明
  
  尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
  
  微博地址: 小灰灰Blog

SpringBoot基础篇AOP之基本使用姿势小结的更多相关文章

  1. SpringCloud基础篇AOP之拦截优先级详解

    前面两篇分别介绍了AOP的基本使用姿势和一些高级特性,当时还遗留了一个问题没有说明,即不同的advice,拦截同一个目标方法时,优先级是怎样的,本篇博文将进行详细分析 同一个切面中,不同类型的advi ...

  2. (二)SpringBoot基础篇- 静态资源的访问及Thymeleaf模板引擎的使用

    一.描述 在应用系统开发的过程中,不可避免的需要使用静态资源(浏览器看的懂,他可以有变量,例:HTML页面,css样式文件,文本,属性文件,图片等): 并且SpringBoot内置了Thymeleaf ...

  3. 视频作品《springboot基础篇》上线了

    1.场景描述 第一个视频作品出炉了,<springboot基础篇>上线了,有需要的朋友可以直接点击链接观看.(如需购买,请通过本文链接购买) 2. 课程内容 课程地址:https://ed ...

  4. SpringBoot基础篇-SpringBoot快速入门

    SpringBoot基础 学习目标: 能够理解Spring的优缺点 能够理解SpringBoot的特点 能够理解SpringBoot的核心功能 能够搭建SpringBoot的环境 能够完成applic ...

  5. Springboot基础篇

    Springboot可以说是当前最火的java框架了,非常适合于"微服务"思路的开发,大幅缩短软件开发周期. 概念 过去Spring充满了配置bean的xml文件,随着spring ...

  6. (一)SpringBoot基础篇- 介绍及HelloWorld初体验

    1.SpringBoot介绍: 根据官方SpringBoot文档描述,BUILD ANYTHING WITH SPRING BOOT (用SPRING BOOT构建任何东西,很牛X呀!),下面是官方文 ...

  7. (三)SpringBoot基础篇- 持久层,jdbcTemplate和JpaRespository

    一.介绍 SpringBoot框架为使用SQL数据库提供了广泛的支持,从使用JdbcTemplate的直接JDBC访问到完整的"对象关系映射"技术(如Hibernate).Spri ...

  8. SpringBoot基础篇(一)

    1.前言 什么是SpringBoot:springboot是当下一套流行的J2EE框架.借助微服务的思想.将业务分成一个个的服务.通过spring-cloud进行整合.最后通过spring-data进 ...

  9. SpringBoot基础系列之自定义配置源使用姿势实例演示

    [SpringBoot基础系列]自定义配置源的使用姿势介绍 前面一篇博文介绍了一个@Value的一些知识点,其中提了一个点,@Value对应的配置,除了是配置文件中之外,可以从其他的数据源中获取么,如 ...

随机推荐

  1. 运放参数的详细解释和分析-part3,输入失调电压Vos及温漂

    运放参数的详细解释和分析-part3,输入失调电压Vos及温漂 在运放的应用中,不可避免的会碰到运放的输入失调电压Vos问题,尤其对直流信号进行放大时,由于输入失调电压Vos的存在,放大电路的输出端总 ...

  2. 【转】深入理解C++的动态绑定和静态绑定 & 不要重定义虚函数中的默认参数

    为了支持c++的多态性,才用了动态绑定和静态绑定.理解他们的区别有助于更好的理解多态性,以及在编程的过程中避免犯错误.需要理解四个名词:1.对象的静态类型:对象在声明时采用的类型.是在编译期确定的.2 ...

  3. BZOJ5343: [Ctsc2018]混合果汁 二分答案+主席树

    分析: 整体二分或二分答案+主席树,反正没有要求强制在线,两个都可以做... 贪心还是比较显然的,那么就是找前K大的和...和CQOI的任务查询系统很像 附上代码: #include <cstd ...

  4. 1.6《想成为黑客,不知道这些命令行可不行》(Learn Enough Command Line to Be Dangerous)——小结

    本章节学过的重要命令整理,见下表Table 2. 命令 描述 例子 echo <string> 向屏幕输出字符串 $ echo hello man <command> 显示命令 ...

  5. 如何判断Android设备是否为模拟器

    android.os.Build.BRAND:获取设备品牌 如果获取的Landroid/os/Build;->BRAND的值为 "generic"则为模拟器上运行. andr ...

  6. Latex数学公式编写

    小叙闲言 一直想用latex来编辑文档,但是没有需求,所以也没有去学习一下,但是最近由于要大量敲数学公式,有了latex数学公式的需求,所以来稍稍总结学习一下 1.在MathType中编写Latex数 ...

  7. 【个人】爬虫实践,利用xpath方式爬取数据之爬取虾米音乐排行榜

    实验网站:虾米音乐排行榜 网站地址:http://www.xiami.com/chart  难度系数:★☆☆☆☆ 依赖库:request.lxml的etree (安装lxml:pip install ...

  8. libgdx学习记录15——音乐Music播放

    背景音乐是游戏中必备的元素,好的背景音乐能为游戏加分不少,使人更容易融入到游戏的氛围中去. Music类中主要有以下函数: play()播放 stop()停止 pause()暂停 setVolume( ...

  9. [UOJ#268]. 【清华集训2016】数据交互[动态dp+可删堆维护最长链]

    题意 给出 \(n\) 个点的树,每个时刻可能出现一条路径 \(A_i\) 或者之前出现的某条路径 \(A_i\) 消失,每条路径有一个权值,求出在每个时刻过后能够找到的权值最大的路径(指所有和该路径 ...

  10. Java设计模式之适配器设计模式(项目升级案例)

    今天是我学习到Java设计模式中的第三个设计模式了,但是天气又开始变得狂热起来,对于我这个凉爽惯了的青藏人来说,又是非常闹心的一件事儿,好了不管怎么样,目标还是目标(争取把23种Java设计模式接触一 ...