大家好,又见面了,我是你们的朋友全栈君。
1.Spring AOP是什么?
Aspect Oriented Programming:面向切面编程 什么时候会出现面向切面编程的需求?按照软件重构的思想,如果多个类中出现重复的代码,就应该考虑定义一个共同的抽象类,将这些共同的代码提取到抽象类中,比如Teacher,Student都有username,那么就可以把username及相关的get、set方法抽取到SysUser中,这种情况,我们称为纵向抽取。 但是如果,我们的情况是以下情况,又该怎么办? 给所有的类方法添加性能检测,事务控制,该怎么抽取? PerformanceMonitor TransactionManager AOP就是希望将这些分散在各个业务逻辑代码中的相同代码,通过横向切割的方式抽取到一个独立的模块中,让业务逻辑类依然保存最初的单纯。
抽取出来简单,难点就是如何将这些独立的逻辑融合到业务逻辑中,完成跟原来一样的业务逻辑,这就是AOP解决的主要问题。
还是看不懂?接下基础案例说明
1.1 基础案例说明
为了更好说明,我们接下来,要讲解的知识点,我们以一个常见的例子来说明 我们以数据库的操作为例来说明:
- 获取连接对象
- 执行SQL(核心业务代码)
- 如果有异常,回滚事务,无异常则提交事务
- 关闭连接
上述的几个部署,“2”是核心业务代码,其他都是非核心业务代码,但是我们又必须写 而面向切面编程就是为了解决这样的问题,将这些非核心业务代码进行抽离,这样开发者只需要关注“核心业务代码”即可。 这样开发效率自然提高。
在项目开发中,SpringAOP是非常常用的技能之一,下面我画一个图来说明,spring都做了什么
2. AOP术语
- 连接点(Joinpoint) 程序执行的某个特定位置,如某个方法调用前,调用后,方法抛出异常后,这些代码中的特定点称为连接点。简单来说,就是在哪加入你的逻辑增强 连接点表示具体要拦截的方法,上面切点是定义一个范围,而连接点是具体到某个方法
- 切点(PointCut) 每个程序的连接点有多个,如何定位到某个感兴趣的连接点,就需要通过切点来定位。比如,连接点–数据库的记录,切点–查询条件 切点用于来限定Spring-AOP启动的范围,通常我们采用表达式的方式来设置,所以关键词是范围
- 增强(Advice) 增强是织入到目标类连接点上的一段程序代码。在Spring中,像BeforeAdvice等还带有方位信息 通知是直译过来的结果,我个人感觉叫做“业务增强”更合适 对照代码就是拦截器定义的相关方法,通知分为如下几种: 前置通知(before):在执行业务代码前做些操作,比如获取连接对象 后置通知(after):在执行业务代码后做些操作,无论是否发生异常,它都会执行,比如关闭连接对象 异常通知(afterThrowing):在执行业务代码后出现异常,需要做的操作,比如回滚事务 返回通知(afterReturning),在执行业务代码后无异常,会执行的操作 环绕通知(around),这个目前跟我们谈论的事务没有对应的操作,所以暂时不谈
- 目标对象(Target) 需要被加强的业务对象
- 织入(Weaving) 织入就是将增强添加到对目标类具体连接点上的过程。 织入是一个形象的说法,具体来说,就是生成代理对象并将切面内容融入到业务流程的过程。
- 代理类(Proxy) 一个类被AOP织入增强后,就产生了一个代理类。
- 切面(Aspect) 切面由切点和增强组成,它既包括了横切逻辑的定义,也包括了连接点的定义,SpringAOP就是将切面所定义的横切逻辑织入到切面所制定的连接点中。 比如上文讨论的数据库事务,这个数据库事务代码贯穿了我们的整个代码,我们就可以这个叫做切面。 SpringAOP将切面定义的内容织入到我们的代码中,从而实现前后的控制逻辑。 比如我们常写的拦截器Interceptor,这就是一个切面类
2.1 一图胜千言
3. Spring概述
1,AOP编程可不是Spring独有的,Spring只是支持AOP编程的框架之一,这一点非常重要,切勿搞反了关系。 2,AOP分两类,一类可以对方法的参数进行拦截,一类是对方法进行拦截,SpringAOP属于后者,所以Spring的AOP是属于方法级的
4. Spring AOP实现-基于注解的方式
@Asoect创建切面类
@Before: 标识一个前置增强方法,相当于BeforeAdvice的功能. @After: final增强,不管是抛出异常或者正常退出都会执行. @AfterReturning: 后置增强,似于AfterReturningAdvice, 方法正常退出时执行. @AfterThrowing: 异常抛出增强,相当于ThrowsAdvice. @Around: 环绕增强,相当于MethodInterceptor. execution:用于匹配方法执行的连接点;
eg.
- 任意公共方法的执行:execution(public * *(..))
- 任何一个以“set”开始的方法的执行:execution(* set*(..))
- AccountService 接口的任意方法的执行:execution(* com.xyz.service.AccountService.*(..))
- 定义在service包里的任意方法的执行: execution(* com.xyz.service.*.*(..))
- 定义在service包和所有子包里的任意类的任意方法的执行:execution(* com.xyz.service..*.*(..))
第一个表示匹配任意的方法返回值, …(两个点)表示零个或多个,第一个…表示service包及其子包,第二个表示所有类, 第三个*表示所有方法,第二个…表示方法的任意参数个数
- 定义在pointcutexp包和所有子包里的JoinPointObjP2类的任意方法的执行:execution(*com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))”)
- pointcutexp包里的任意类: within(com.test.spring.aop.pointcutexp.*)
- pointcutexp包和所有子包里的任意类:within(com.test.spring.aop.pointcutexp..*)
- 实现了Intf接口的所有类,如果Intf不是接口,限定Intf单个类:this(com.test.spring.aop.pointcutexp.Intf)
- 当一个实现了接口的类被AOP的时候,用getBean方法必须cast为接口类型,不能为该类的类型
- 带有@Transactional标注的所有类的任意方法: @within(org.springframework.transaction.annotation.Transactional) @target(org.springframework.transaction.annotation.Transactional)
- 带有@Transactional标注的任意方法: @annotation(org.springframework.transaction.annotation.Transactional) @within和@target针对类的注解,@annotation是针对方法的注解
- 参数带有@Transactional标注的方法:@args(org.springframework.transaction.annotation.Transactional)
- 参数为String类型(运行是决定)的方法: args(String) 至于@Around解析请跳转:
- https://blog.csdn.net/qq_41981107/article/details/85260765 参考博客: https://my.oschina.net/itblog/blog/211693 https://my.oschina.net/u/3434392/blog/1625493
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/169593.html原文链接:https://javaforall.cn