当前位置: 首页 > java >正文

Spring AOP(1)

1.AOP                                                                                                                                                      Spring有两大核心思想,IoC和AOP.前面已经介绍过IoC了,这里接着介绍AOP,AOP:Aspect Oriented Program(面向切面编程),面向切面编程,切面就是指某一类特定问题,所以AOP也可以理解为面向特定方法编程.面向特定方法编程?在前面介绍的拦截器,可以实现登录拦截,即是对"登录校验"这一类问题的统一处理,所以拦截器是AOP思想的一种实现,同样的统一数据返回和统一异常处理也是AOP思想的一种实现.简单来说:AOP是一种思想,是对某一类事情的集中处理.Spring AOP是AOP思想的一种实现方式.当然Spring AOP的应用远不止于此.现在有一个项目,项目中有很多的业务功能:现在发现有一些业务的执行效率比较低,耗时较长,现在需要找出这些耗时较长的业务方法,进行优化.传统的方法是,统计出每一个业务方法的耗时时间,计较得出.可以通过下面的方法,粗略算出时间,并进行比较:但是一个项目中通常有很多方法,如果对于每个方法都添加这写重复的代码,这样不是十分合理.对于同一类问题的处理,AOP就可以做到在不改动原始方法的基础上,针对特定的方法进行功能的增强.

2.Spring AOP介绍(为了方便介绍,这里在一个图书管理系统中进行演示)

首先需要引入下面的依赖接着编写AOP程序,计算程序运行的时间.这里计算Controller层各个方法的运行时间:观察日志:可以看到这里显示了方法的耗时时间.不用重复编码.这里:@Aspect:标识这是一个切面类    @Around:环绕通知,在目标方法的前后都会被执行,后面的表达式表示对哪些方法进行增强.ProceedingJoinPoint.proceed()让原始方法执行.通过上面这个简单的程序可以感受到AOP面向切面编程的优势:代码无入侵,减少了重复代码,提高了开发效率,维护方便.

3.Spring AOP详解

3.1Spring AOP核心概念

 Pointcut(切点)                                                                                                                               切点,也称之为"切入点",Pointcut的作用就是提供一组规则,告诉程序对哪些方法进行功能增强.上面的表达式就是切点表达式.                                                                                                            Join Point(连接点)                                                                                                                            满足切断表达式规则的方法,就是连接点.也就是可以被AOP控制的方法.那么上面的切点表达式中所有 com.example.demo.controller路径中的方法,都是连接点.          上面/user和/book下的所有方法,都是连接点.连接点是满足切点表达式的元素,切点可以看作是保存了众多连接点的集合.                                                                                                                          Advice(通知):通知就是具体要做的工作,那些重复的代码.上面计算方法执行时间的代码就是通知.                                                                                               Aspect(切面):切面(Aspect)=切点(Pointcut)+通知(Advice),通过切面就能够知道当前AOP程序要对那些方法执行什么样的操作.切面即包含了通知逻辑的定义,也包含了连接点的定义.这个整体就是切面,切面所在的类,称之为切面类(被@Aspect注解标识的类)

3.2通知类型:Spring中的通知类型有下面的几种                                                                                  @Around:环绕通知,此注解标识的通知方法在目标方法前后都会执行                                                @Before:前置通知,此注解标识的通知方法在目标方法前执行                                                            @After:后置通知,此注解标识的通知方法在目标方法之后执行,且无论是否发生异常都会执行.           @AfterReturning:返回后通知,此注解标识的通知方法在目标方法后被执行,有异常不会执行.            @AfterThrowing:异常后通知,此注解标识的通知方法发生异常后执行.下面是一个例子:在对应目录下写一些测试:这里执行正常的方法:可以看见,正常运行时,@AfterThrowing表示的通知方法不会执行.正常情况下,不同类型的通知,执行顺序如下:执行会发生异常的方法:这里可以看到,@AfterReturning标识的通知方法不会执行,@AfterThrowing标识的通知方法执行了.@Around环绕通知中原始方法调用时有异常,通知中的环绕后的代码逻辑也不会再执行了(因为原始方法调用出异常了)出现异常时的执行顺序.注意事项:

@Around环绕通知需要调用ProceedingJoinPoint.proceed()来让原始方法执行,其他通知不需要考虑目标方法执行.                                                                                                                                  @Around环绕通知方法的返回值,必须指定为Object,来接收原始方法的返回值.否则原始方法执行完毕,是获取不到返回值的.                                                                                                                      3.3@PointCut:上述代码存在一个问题,就是存在大量重复的切点表达式"execution(* com.example.demo.controller.*.*(..))",Spring提供了@PointCut注解,把公共的切点表达式提取出来,可以避免重复代码的编写.如果想在其他切面类中使用当前定义的切点时,除了需要把private改为public,还要注意引用方式,引用方式为:全限定类名.方法名().

3.4切面优先级@Order,当在一个项目中,定义了多个切面类时,并且这些切面类的多个切点都匹配到了同一个方法.当目标方法执行的时候,这些切面类中的方法都会执行,那么这些方法的执行顺序是怎样的呢?下面通过一个例子使用@Before和@After来进行验证:存在多个切面类同时执行时,默认按照类名的字母顺序降序执行,@Before:字母顺序在前面的先执行@After:字母顺序在前面的后执行.这种方法还是不方便一眼看出执行顺序,可以通过@Order注解来控制这些切面通知的执行顺序.这里的执行结果如下:可以看到order中定义数字越小的通知,before越先执行,after越后执行.@orderko控制切面的有限级,先执行优先级较高的切面,后执行优先级较低的切面,最终执行目标方法.3.5切点表达式  

上面的表达式中,使用的是execution(....),根据方法签名来匹配方法.execution(...)的语法为:                  execution(<访问修饰符><返回类型><包名.类名.方法(方法参数)><异常>),其中的返回类型和异常可以省略.上面这个表达式使用的是execution,省略了访问修饰符和异常,返回类型为*,<包名.类名.方法(方法参数)>,一一对应.切点表达式支持通配符表达,*:匹配任意字符,只能匹配一个元素.类名使用*时,表示匹配任意类,包名使用*时表示匹配任意包,方法名使用*时,表示匹配任意方法.参数使用使用*时,表示一个任意类型的参数.  ..:匹配多个连续的符号,可以通配任意层级的包,或任意类型,任意个数的参数.使用..配置报名,表示此包和此包下的所有子包   可以使用..配置参数,表示匹配任意个类型的参数.下面这个例子表示:这个例子表示,com.example.demo.controller包下的TestController类下的t1方法,参数为无,访问修饰符为public 返回值类型为String,并且省略了异常. 如果省略访问修斯符:匹配所有返回值类型匹配TestController下的所有无参方法:匹配TestController下的所有方法:匹配controller包下的所有方法:其他情况依次匹配就好.                                                                                                                       上面介绍的是使用execution表达式来进行匹配方法,但是exectuion也有不适合的情景,比如我们要匹配TestController下的t1()方法和TestController下的t2()方法,这时候再使用execution这种切点表的是就显得不太方便了.这种情况可以使用@annotation来描述这一类的切点.实现步骤:  1.编写自定义注释  2.使用@annotation表达式来描述切点 3.在连接点的方法上添加自定义注解.                                     对这些代码进行测试:首先自定义注解@MyAspect.              @Target标识了Annotation所修饰的对象范围,即该注解可以作用在什么地方.ElementType.METHOD:用来描述方法. @Retention:指Annotation被保留的时间长短,标明注释的生命周期.RetentionPolicy.RUNTIME.RUNTIME:运行时注解,表明注释存在于源代码,字节码和运行时中.意味着在编译时,字节码中和实际运行时都可以通过反射获取到该注解的信息,通常用于一些需要在运行时处理的注解,比如@Controller,@ResponseBody.                                                           定义切面类:使用@annotation切点表达式定义切点,只对@MyAspect生效.在测试方法上添加自定义的注解:这里如果想在u1和t1方法上添加注解,使用execution()是不易实现的,这里使用@MyAspect自定义注解.这里分别对test下的两个方法和user下的两个方法都发出请求,结果如下:

http://www.xdnf.cn/news/10826.html

相关文章:

  • 小家电外贸出口新利器:WD8001低成本风扇智能控制方案全解析
  • 模块化交互数字人系统:OpenAvatarChat,单台PC即可运行完整功能
  • sourcetree中的mercurial有什么用
  • Python实例题:Flask实现简单聊天室
  • 【PCB设计】STM32开发板——原理图设计(电源部分)
  • FLgo学习
  • leetcode46.全排列:回溯算法中元素利用的核心逻辑
  • MyBatis 一级缓存与二级缓存
  • 【Python进阶】装饰器
  • 基于白鲸优化算法的路径优化研究
  • 数字化赋能智能托育实训室课程体系
  • 工业透明材料应力缺陷难检测?OAS 软件应力双折射案例来解决
  • ADK实战-基于ollama+qwen3实现外部工具串行调用
  • 帝可得 - 运营管理APP
  • MMAD论文精读
  • day20 奇异值SVD分解
  • 线程池和数据库连接池的区别
  • 3-10单元格行、列号获取(实例:表格选与维度转换)学习笔记
  • 163MusicLyrics(歌词下载工具) v7.0
  • MDP的observations部分
  • MS9288C+MS2131 1080P@60Hz USB3.0环出采集
  • 常见的七种排序算法 ——直接插入排序
  • 个人博客系统自动化测试报告
  • 最佳实践 | 璞华易研“PLM+AI智能研发平台”,助力汉旸科技实现高新材料“数据驱动研发”
  • 95. Java 数字和字符串 - 操作字符串的其他方法
  • OpenEMMA: 打破Waymo闭源,首个开源端到端多模态模型
  • 蓝绿部署解析
  • Python爬虫监控程序设计思路
  • 统信 UOS 服务器版离线部署 DeepSeek 攻略
  • 飞牛fnNAS存储模式RAID 5数据恢复