关于Spring AOP的两个高级功能你用过吗?

文摘   2025-01-07 08:00   新疆  

Spring Boot 3实战案例合集》现已囊括超过70篇精选实战文章,并且此合集承诺将永久持续更新,为您带来最前沿的技术资讯与实践经验。欢迎积极订阅,享受不断升级的知识盛宴!订阅用户将特别获赠合集内所有文章的最终版MD文档(详尽学习笔记),以及完整的项目源码,助您在学习道路上畅通无阻。

【重磅发布】《Spring Boot 3实战案例锦集》PDF电子书现已出炉!

🎉🎉我们精心打造的《Spring Boot 3实战案例锦集》PDF电子书现已正式完成,目前已经有70个案例,后续还将继续更新。文末有电子书目录。

📚📚订阅获取
只需订阅我们的合集点我订阅,即可立即私信我们获取这本珍贵的电子书。轻松拥有Spring Boot 3的实战宝典!

💪💪永久更新承诺
我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务。这意味着,随着技术的不断发展和Spring Boot 3的深入应用,我们的电子书也将持续更新,确保您始终掌握最前沿、最实用的技术知识。

🔥🔥精彩内容不容错过
《Spring Boot 3实战案例锦集》汇聚了众多精心挑选的实战案例,旨在帮助您快速掌握Spring Boot 3的核心技术和实战技巧。无论您是初学者还是有一定经验的开发者,都能从中受益匪浅。

💌💌如何获取
请立即订阅我们的合集点我订阅,并通过私信联系我们,我们将第一时间将电子书发送给您。

现在就订阅合集


环境:SpringBoot3.2.5



1. 引入功能

Spring AOP中有非常特殊的类型增强"Introductions",它允许切面为被代理的对象动态地引入新的接口,从而使得这些对象在运行时具备了这些接口所声明的方法。

工作原理:

定义接口:首先,声明一个你需要目标类实现的接口。在目标类创建代理时,代理类会实现该接口

实现接口:这是对上面接口的实现,当我们通过代理类调用上面声明的接口时内部会调用该实现接口对应的方法。

创建切面:在切面中,通过@DeclareParents注解(Spring AOP的特定功能)来声明哪些目标对象将被引入什么接口。这个注解实际上是在创建代理对象时,将这些接口的实现动态地“插入”到代理对象中。

有点晦涩,接下来直接上代码你就明白怎么一回事了。

定义接口

public interface DAO {  void remove() ;}

该接口会被代理类实现。

实现上面的接口

public class DefaultDAO implements DAO {  @Override  public void remove() {    System.out.println("默认删除功能") ;  }}

最终生成的代理类实现了DAO接口,而具体方法实现细节是调用这里的DefaultDAO。

创建切面

接下来就是定义切面,你需要增强的类及声明接口(代理类要实现的接口)。

@Aspectpublic class LogAspect {  @Pointcut("@annotation(log)")  private void recordLog(Log log) {}    // 通过该注解声明PersonService类,在生成代理时需要实现DAO接口  // 并且调用DAO中的方法时是调用的这里DefaultDAO中实现的方法  @DeclareParents(value = "com.pack.aop.PersonService", defaultImpl = DefaultDAO.class)  private DAO dao ;    @Around("recordLog()")  public Object aroundLog(ProceedingJoinPoint pjp) throws Throwable {    System.out.println("日志执行前...") ;    Object ret = pjp.proceed() ;    System.out.println("日志执行后...") ;    return ret ;  }}

声明PersonService

@Servicepublic class PersonService {  public void save() {    System.out.println("保存Person对象") ;  }}

接下来进行测试

@SpringBootTestpublic class AppTest {  private final PersonService ps ;  public AppTest(PersonService ps) {    this.ps = ps ;  }  @Test  public void testSave() {    this.ps.save() ;    // 判断是否是DAO类型    if (ps instanceof DAO dao) {      dao.remove() ;     }  }}

输出结果

日志执行前...保存Person对象日志执行后...默认删除功能

PersonService生成的代理类,同时也实现了DAO接口,方法调用是DefaultDAO中的实现。

2. 切面实例化模型

看标题又是一个晦涩的东西。在Spring AOP中,切面实例化模型主要关注于切面对象是如何被创建和管理的。Spring提供了几种不同的方式来实例化切面,每种方式都有其特定的用途和优点。这其中包括:perthis、pertarget 和 pertypewithin 实例化模型。这里我们就介绍perthis和pertarget。

perthis

perthis子句的作用是为每个执行业务服务的唯一服务对象创建一个方面实例(每个与此方面在连接点匹配的绑定到此对象的唯一对象)

pertarget

pertarget 实例化模型的工作方式与 perthis 完全相同,但它会在匹配的连接点上为每个唯一的目标对象创建一个方面实例。

示例:

定义切面

@Component@Scope("prototype")@Aspect("perthis(execution(* com.pack.aop.DAO.*(..)))")public class LogAspect {  @Before("bean(*Service)")  public void beforeLog(JoinPoint jp) {    System.out.println("before 记录日志 - " + this) ;  }}

业务对象

public interface DAO {  public void save() ;}public class PersonService implements DAO {  public void save() {    System.out.println("保存Person对象") ;  }}public class StudentService implements DAO {  public void save() {    System.out.println("保存Student对象") ;  }}

测试

@SpringBootTestpublic class AppTest {  @Resource  private PersonService ps ;  @Resource  private StudentService ss ;  @Test  public void testAll() {    ps.save();    System.out.println("===============") ;    ss.save();  }}

输出结果

before 记录日志 - com.pack.aop.LogAspect@3ed242a4保存Person对象====================before 记录日志 - com.pack.aop.create.LogAspect@73a2e526保存Student对象

实例化切面模型除非你需要更细粒度控制切面实例生命周期的场景下使用,一般应该是很少使用的。

以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏

推荐文章

实战!16条SpringBoot Web服务配置指南及优化技巧

RabbitMQ非常实用技巧,动态调整消息并发处理能力

强大!SpringBoot结合STOMP简化数据实时通信

优雅重构Spring Boot代码,我用这6种策略消灭if else

强大!实时监控SpringBoot运行时状态及应用运行时信息(数据库, Redis,MQ等)

管理SpringBoot项目的3个强大的功能是否用过?

这才是SpringBoot统一响应和异常处理的最佳实践

请一定掌握SpringBoot这4个高级开发技巧

SpringBoot强大的数据格式化功能

严重!Spring AOP Bug导致切面重复执行

Spring Boot启动时必须对配置信息做有效性校验

Spring注入还可以这样玩!涨知识了

SpringBoot3使用虚拟线程一定要小心了

Spring全家桶实战案例源码
spring, springboot, springcloud 案例开发详解
 最新文章