SpringBoot基础篇AOP之基本使用姿势小结

  一般来讲,谈到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

原文地址:https://www.cnblogs.com/qwangxiao/p/10460730.html

时间: 2024-09-28 22:50:58

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

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

一.描述 在应用系统开发的过程中,不可避免的需要使用静态资源(浏览器看的懂,他可以有变量,例:HTML页面,css样式文件,文本,属性文件,图片等): 并且SpringBoot内置了Thymeleaf模板引擎,可以使用模板引擎进行渲染处理,默认版本为2.1,可以重新定义Thymeleaf的版本号,在maven的配置文件中配置如下内容: <properties> <thymeleaf.version>3.0.2.RELEASE</thymeleaf.version> &l

Springboot基础篇

Springboot可以说是当前最火的java框架了,非常适合于"微服务"思路的开发,大幅缩短软件开发周期. 概念 过去Spring充满了配置bean的xml文件,随着spring2.x和JDK1.5带来注解,配置大量减少,到了目前的Spring4.x和Spring Boot,更是推荐java配置的方式(这点和.NET很相似). 总体来说,Spring框架是轻量级企业开发一个完整解决方案,通过Ioc容器来管理pojo对象,其具有模块化的特点,基本的模块如下: 核心容器:Spring-C

2000条你应知的WPF小姿势 基础篇&lt;1-7&gt;

在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师,对C#和WPF有着极深的热情.最为出色的是他维护了两个博客:2,000Things You Should Know About C# 和 2,000 Things You Should Know About WPF .听到博客名字就懂这个人有多伟大了吧.他以类似微博式的150字简短语言来每天更新一条WPF和C#重要又容易被遗忘的知识.Follow他的博客也有一段日子了,很希望能够分享给大家. 本系列我不仅会翻译

2000条你应知的WPF小姿势 基础篇&lt;63-68 Triggers和WPF类逻辑结构&gt;

原文:2000条你应知的WPF小姿势 基础篇<63-68 Triggers和WPF类逻辑结构> 在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000ThingsYou Should Know About C# 和 2,000 Things You Should Know About WPF .他以类似微博式的150字简短语言来每天更新一条WPF和C#重要又容易被遗忘的知识.很希望能够分享给大家. 本系列我不仅会翻译他的每

2000条你应知的WPF小姿势 基础篇&lt;8-14&gt;

在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师,对C#和WPF有着极深的热情.最为出色的是他维护了两个博客:2,000Things You Should Know About C# 和 2,000 Things You Should Know About WPF .听到博客名字就懂这个人有多伟大了吧.他以类似微博式的150字简短语言来每天更新一条WPF和C#重要又容易被遗忘的知识.Follow他的博客也有一段日子了,很希望能够分享给大家. 本系列我不仅会翻译

SpringBoot图文教程「概念+案例 思维导图」「基础篇上」

有天上飞的概念,就要有落地的实现 概念+代码实现是本文的特点,教程将涵盖完整的图文教程,代码案例 每个知识点配套自测面试题,学完技术自我测试 本文初学向,所以希望文中所有的代码案例都能敲一遍 大哥大姐新年好,点赞转发不要少 **文本已收录至GitHub开源仓库 Lu_JavaNodes 码云仓库地址Lu_JavaNodes ,**包含教程涉及所有思维导图,案例代码和后续讲解视频,欢迎Star增砖添瓦. 前言 庚子鼠年,封村儿,在试过了睡觉,打麻将,做凉皮,做蛋糕之后,我不由的陷入了对人生和社会的

Spring Cloud Alibaba | Sentinel: 服务限流基础篇

目录 Spring Cloud Alibaba | Sentinel: 服务限流基础篇 1. 简介 2. 定义资源 2.1 主流框架的默认适配 2.2 抛出异常的方式定义资源 2.3 返回布尔值方式定义资源 2.4 注解方式定义资源 2.5 异步调用支持 3. 规则的种类 3.1 流量控制规则 (FlowRule) 3.2 熔断降级规则 (DegradeRule) 3.3 系统保护规则 (SystemRule) 3.4 访问控制规则 (AuthorityRule) Spring Cloud Al

WebBug靶场基础篇 — 03

基础篇 6 - 16 关... 在记录之前,先说一件事 = =! 小学生真多 = =!好心提供一个靶场,玩玩就算了,他挂黑页 ?现在好了,以后这个靶场不对外啊!你高兴了?爽了吧? 都是新手过来的,好心搭个公网的漏洞网站,还真有挂黑页的... 第六关... 这个关卡设置的有点问题,只有一个登陆框,也没给提示账号密码,弱密码也试了好几波,都没进去 = =!然后我就去数据库里看看密码 = =! 毕竟源码设计的还是有问题,然后我就开始登陆了. 看到这里,直接抓包,毕竟不就是一个修改参数的漏洞嘛... 是

Android Fragment使用(一) 基础篇 温故知新

Fragment使用的基本知识点总结, 包括Fragment的添加, 参数传递和通信, 生命周期和各种操作. Fragment使用基础 Fragment添加 方法一: 布局里的标签 标识符: tag, id, 如果都没有, container的id将会被使用. 方法二: 动态添加 动态添加利用了一个transaction: FragmentManager fragmentManager = getFragmentManager(); Fragment fragment = fragmentMan