spring中最重要的两个部分 1.ioc 控制反转 2.aop面向切面编程 博主之前有一篇文章是关于SpringioC的理解:关于SpringIOC的理解有需要的小伙伴可以自行跳转。
博主之前有一篇文章是关于SpringioC的理解:关于SpringIOC的理解有需要的小伙伴可以自行跳转。
下面,我们今天来一起学习下SpringAOP相关的知识点。SpringAOP的英文全称是——(Aspect-Oriented Programming)面向切片编程,切片的理解大家可以想象一下切片面包,一个面包整体就是我们的项目,而把面包从业务的角度切成一片一片的,这些切片就是我们的业务。我们来举一个例子,比如下面这张图:
在我们没有使用SpringAOP时,我们想要实现一个电商项目的日志追踪功能,我们需要在我们的每个业务层中都去添加这一功能相关的代码,繁琐而且缠绕,比如登录Service中本来只需要处理登录业务相关的代码逻辑,但是却不得不加入输出打印日志相关的代码。但是使用了AOP面向切面编程之后:
我们只需要在controller 和 service中间切上那么一刀,把我们的日志追踪功能添加进去,然后通知Spring,并标注切入点。我们就可以实现业务之间的解耦,让每一块单独的业务只关心自己当前模块的相关业务。代码不再缠绕。总结一下:
面向切面的编程(AOP)实现了横切关注的模块化, 横切关注的代码都在一个地方
关注点分离: 如 日志关注点从业务代码中独立出来, 业务模块不用再关心日志问题.
解决了:
代码缠绕, 关注点耦合
代码分散, 同样的关注分散在各个模块
那么我们如何去使用SpringAOP中的功能呢?
我们在Maven中导入SpringAOP的相关依赖,
org.springframework.boot spring-boot-starter-aop
通过@Aspect注解标注这个是切面组件
就是通知Spring在什么之前执行以下相关代码,如上代码段中就是告诉Spring,要在personServiceImpl这个业务实现类中的所有方法前执行,如果需要标注具体方法,可以通过@Pointcut统一管理切入点。
@Aspect //表示这就是切面@Component//组件注解public class DemoAspect { private static Logger logger LoggerFactory.getLogger(DemoAspect.class); @Before("bean(personServiceImpl)") public void log(JoinPoint joinPoint){ // Signature: 签名, 这里是方法签名 // 方法签名: 方法名 + 参数列表 Signature signature = joinPoint.getSignature(); logger.debug("方法前记录下用户行为:{} 时间执行了 {}", LocalDateTime.now(), signature); }}
连接点(JoinPoint)
切入点 Pointcut
Advice 通知
切面 Aspect
编织(织入)
@AfterReturning(value = "bean(personServiceImpl)", returning = "result")public void test2(JoinPoint joinPoint, Object result){ Signature signature = joinPoint.getSignature(); logger.debug("方法正常结束记录下用户行为:{} 时间执行了 {}, 返回值:{}", LocalDateTime.now(), signature, result);}@AfterThrowing(value = "bean(personServiceImpl)", throwing = "e")public void test3(JoinPoint joinPoint, Exception e){ Signature signature = joinPoint.getSignature(); logger.debug("方法异常结束记录下用户行为:{} 时间执行了 {} 异常: {}", LocalDateTime.now(), signature, e.getMessage());}
@Aspect //切面组件, 注解, 来自 aspectj@Componentpublic class DemoAspect { private static Logger logger = LoggerFactory.getLogger(DemoAspect.class); @Pointcut("bean(personServiceImpl)") public void personService(){} @Before("personService()") public void log(JoinPoint joinPoint){ // Signature: 签名, 这里是方法签名 // 方法签名: 方法名 + 参数列表 Signature signature = joinPoint.getSignature(); logger.debug("方法前记录下用户行为:{} 时间执行了 {}", LocalDateTime.now(), signature); } @After("personService()") public void test(JoinPoint joinPoint){ Signature signature = joinPoint.getSignature(); logger.debug("方法后记录下用户行为:{} 时间执行了 {}", LocalDateTime.now(), signature); } @AfterReturning(value = "personService()", returning = "result") public void test2(JoinPoint joinPoint, Object result){ Signature signature = joinPoint.getSignature(); logger.debug("方法正常结束记录下用户行为:{} 时间执行了 {}, 返回值:{}", LocalDateTime.now(), signature, result); } @AfterThrowing(value = "personService()", throwing = "e") public void test3(JoinPoint joinPoint, Exception e){ Signature signature = joinPoint.getSignature(); logger.debug("方法异常结束记录下用户行为:{} 时间执行了 {} 异常: {}", LocalDateTime.now(), signature, e.getMessage()); }}
在连接点(JoinPoint)环绕执行
@Around 可以替代: @Before @After 等全部通知
@Around("personService()")public Object demo(ProceedingJoinPoint joinPoint) throws Throwable{ Signature signature = joinPoint.getSignature(); logger.debug("在连接点{}之前", signature); Object value = joinPoint.proceed(); //执行目标连接点方法 logger.debug("在连接点{}之后", signature); // 狸猫换太子: 替换返回值的演示 // Around 通知中, 可以对返回值进行加工处理, 实现丰富的行为 // if (value instanceof List){ // value = new ArrayList<>(); // } return value;}
使用注意事项:
@Around 的连接点类型 ProceedingJoinPoint, 表示被执行是方法
joinPoint.proceed() 表示执行连接点方法
如果不执行, 就意味着连接点方法被放弃! 这种行为可能是一个有害行为
joinPoint.proceed() 的返回值是连接方法的返回值, 原则上要作为当前方法的返回值
joinPoint.proceed() 的异常就是连接点方法执行异常, 如果进行拦截处理, 就意味着影响异常处理流程.
@Around 的功能强大, 可以处理返回值, 可以处理异常, 可以在切入点方法前嵌入代码, 可以在切入点方法之后嵌入代码.
请谨慎使用 @Around
--结束END--
本文标题: SpringAOP初识——初学者向
本文链接: https://lsjlt.com/news/386704.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-10-23
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0