😀前言
本篇的Spring-AOP系类文章第三篇因为我们前面采用原始的方式实现了一次所有本篇我们来详细Spring-AOP的的全面使用
🧑个人简介:大家好,我是尘觉,希望我的文章可以帮助到大家,您的满意是我的动力😉😉
😀再次分析-提出 Spring AOP-真正的AOP
- 土方法 不够灵活
- 土方法 复用性差
- 土方法 还是一种硬编码(因为没有注解和反射支撑)
- Spring AOP 闪亮登场-底层是 ASPECTJ
- 有了前面的技术引导,理解 Spring AOP 就水到渠成
AOP 的基本介绍
● 什么是 AOP
AOP 的全称(aspect oriented programming) ,面向切面编程
● 示意图说明 AOP 的相关概念
一张详细图说明 AOP
😆● AOP 实现方式
- 基于动态代理的方式[内置 aop 实现]
- 使用框架 aspectj 来实现
AOP 编程快速入门
● 说明
需要引入核心的 aspect 包
在切面类中声明通知方法
- 前置通知:@Before
- 返回通知:@AfterReturning
- 异常通知:@AfterThrowing
- 后置通知:@After
- 环绕通知:@Around
编辑五种通知和前面写的动态代理类方法的对应关系
😮快速入门实例
● 需求说明
我们使用 aop 编程的方式,来实现手写的动态代理案例效果,就以上一个案例为例来讲解
● 代码实现步骤
导入 AOP 编程需要的jar
创建 SmartAnimalable接口
public interface SmartAnimalable { //求和 float getSum(float i, float j); //求差 float getSub(float i, float j); }
创建SmartDog
注意加入注解@Component
@Component //使用@Component 当spring容器启动时,将 SmartDog注入到容器 public class SmartDog implements SmartAnimalable { @Override public float getSum(float i, float j) { float result = i + j; //result = 1 / 0; //模拟一个算术异常 System.out.println("方法内部打印result = " + result); return result; } @Override public float getSub(float i, float j) { float result = i - j; System.out.println("方法内部打印result = " + result); return result; } }
创建 SmartAnimalAspect类
SmartAnimalAspect 作用就是接管切面编程 , 此时原来的 MyProxyProvider 类就可以拿掉了
@Aspect //表示是一个切面类[底层切面编程的支撑(动态代理+反射+动态绑定...)] @Component //会注入SmartAnimalAspect到容器 public class SmartAnimalAspect { /** * * 1. @Before 表示前置通知:即在我们的目标对象执行方法前执行 * 2. value = "execution(public float com.spring.aop.aspectj.SmartDog.getSum(float, float) * 指定切入到哪个类的哪个方法 形式是: 访问修饰符 返回类型 全类名.方法名(形参列表) * 3. showBeginLog方法可以理解成就是一个切入方法, 这个方法名是可以程序员指定 比如:showBeginLog * 4. JoinPoint joinPoint 在底层执行时,由AspectJ切面框架, 会给该切入方法传入 joinPoint对象 * , 通过该方法,程序员可以获取到 相关信息 * * @param joinPoint */ @Before(value = "execution(public float com.spring.aop.aspectj.SmartDog.getSum(float, float))") public void showBeginLog(JoinPoint joinPoint) { //通过连接点对象joinPoint 可以获取方法签名 Signature signature = joinPoint.getSignature(); System.out.println("SmartAnimalAspect-切面类showBeginLog()[使用的myPointCut()]-方法执行前-日志-方法名-" + signature.getName() + "-参数 " + Arrays.asList(joinPoint.getArgs())); } // 返回通知:即把showSuccessEndLog方法切入到目标对象方法正常执行完毕后的地方 // 1. 如果我们希望把目标方法执行的结果,返回给切入方法 // 2. 可以再 @AfterReturning 增加属性 , 比如 returning = "res" // 3. 同时在切入方法增加 Object res // 4. 注意: returning = "res" 和 Object res 的 res名字一致 // @AfterReturning(value = "execution(public float com.spring.aop.aspectj.SmartDog.getSum(float, float))", returning = "res") // 使用切入点 @AfterReturning(value = "execution(public float com.hspedu.spring.aop.aspectj.SmartDog.getSum(float, float))", returning = "res") public void showSuccessEndLog(JoinPoint joinPoint, Object res) { Signature signature = joinPoint.getSignature(); System.out.println("SmartAnimalAspect-切面类showSuccessEndLog()-方法执行正常结束-日志-方法名-" + signature.getName() + " 返回的结果是=" + res); } //异常通知:即把showExceptionLog方法切入到目标对象方法执行发生异常的的catch{} @AfterThrowing(value = "execution(public float com.spring.aop.aspectj.SmartDog.getSum(float, float))", throwing = "throwable") public void showExceptionLog(JoinPoint joinPoint, Throwable throwable) { Signature signature = joinPoint.getSignature(); System.out.println("SmartAnimalAspect-切面类showExceptionLog()-方法执行异常-日志-方法名-" + signature.getName() + " 异常信息=" + throwable); } //最终通知:即把showFinallyEndLog方法切入到目标方法执行后(不管是否发生异常,都要执行 finally{}) @After(value = "execution(public float com.spring.aop.aspectj.SmartDog.getSum(float, float))") public void showFinallyEndLog(JoinPoint joinPoint) { Signature signature = joinPoint.getSignature(); System.out.println("SmartAnimalAspect-切面类showFinallyEndLog()-方法最终执行完毕-日志-方法名-" + signature.getName()); } }
😋解读
@Before
- @Before 表示前置通知:即在我们的目标对象执行方法前执行
- value = "execution(public float com.spring.aop.aspectj.SmartDog.getSum(float, float)指定切入到哪个类的哪个方法 形式是: 访问修饰符 返回类型 全类名.方法名(形参列表)
- showBeginLog方法可以理解成就是一个切入方法, 这个方法名是可以程序员指定 比如:showBeginLog
- JoinPoint joinPoint 在底层执行时,由AspectJ切面框架, 会给该切入方法传入 joinPoint对象, 通过该方法,程序员可以获取到 相关信息
@AfterReturning
返回通知:即把showSuccessEndLog方法切入到目标对象方法正常执行完毕后的地方
- 如果我们希望把目标方法执行的结果,返回给切入方法
- 可以再 @AfterReturning 增加属性 , 比如 returning = “res”
- 同时在切入方法增加 Object res
- 注意: returning = “res” 和 Object res 的 res名字一致
@AfterReturning(value = “execution(public float com.spring.aop.aspectj.SmartDog.getSum(float, float))”, returning = “res”)
使用切入点
@AfterThrowing
异常返回:在异常通知方法中获取异常信息 可以增加属性如 throwing = “throwable”
即public void showExceptionLog(JoinPoint joinPoint, Throwable throwable
注意:throwing = “throwable” 和 showExceptionLog 的 Throwable throwable名字一致
异常通知:即把showExceptionLog方法切入到目标对象方法执行发生异常的的catch{}
@After
最终通知:即把showFinallyEndLog方法切入到目标方法执行后(不管是否发生异常,都要执行 finally{})
创建 src\beans6.xml 并配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <context:component-scan base-package="com.spring.aop.aspectj"/> <!-- 开启基于注解的AOP功能 --> <aop:aspectj-autoproxy/> </beans>
测试
@Test public void testDoAround() { //得到spring容器 ApplicationContext ioc = new ClassPathXmlApplicationContext("beans08.xml"); SmartAnimalable smartAnimalable = ioc.getBean(SmartAnimalable.class); smartAnimalable.getSum(10, 2); }
细节说明
- 关于切面类方法命名可以自己规范一下,
比如 showBeginLog() . showSuccessEndLog() showExceptionLog(), showFinallyEndLog()
- 切入表达式的更多配置,比如使用模糊配置
@Before(value=“execution(* com.hspedu.aop.proxy.SmartDog.*(…))”)
- 表示所有访问权限,
所有包的下所有有类的所方法,都会被执行该前置通知方法
@Before(value=“execution(* .(…))”)
- 当 spring 容器开启了 < aop:aspectj-autoproxy/> ,
我们获取注入的对象, 需要以接口的类型来获取, 因为你注入的对象.getClass() 已经是代理类型了!
- 当 spring 容器开启了 < aop:aspectj-autoproxy/> ,
我们获取注入的对象, 也可以通过 id 来获取, 但是也要转成接口类型
7.如果每回使用注解来配置的时候都要写类的全路径麻烦可以考虑
//定义一个切入点, 在后面使用时可以直接引用, 提高了复用性
@Pointcut(value = “execution(public float com.spring.aop.aspectj.SmartDog.getSum(float, float)))”)
public void myPointCut() {}
使用如前面的
前面的@Before(value = “execution(public float com.hspedu.spring.aop.aspectj.SmartDog.getSum(float, float))”)
//这里我们使用定义好的切入点
可以写成@Before(value = “myPointCut()”)
@AfterReturning(value = “myPointCut()”, returning = “res”)
其他的类似使用
- 如果有多个切面类需要定义顺序可以使用
@Order(value = 2)//表示该切面类执行的顺序, value的值越小, 优先级越高
😄总结
本篇下详细的讲解了Spring-AOP的全面使用加上代码分析
😍Spring-AOP系类文章
第一篇-> Spring-AOP的基本介绍以及通过先动态代理方式实现
第二篇-> Spring-动态代理深入了解
文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起来评论区一起讨论😁
希望能和诸佬们一起努力,今后我们一起观看感谢您的阅读🍻
如果帮助到您不妨3连支持一下,创造不易您们的支持是我的动力🤞