Spring AOP

1. 什么是 AOP

AOP (Aspect Orient Programming),直译过来就是 面向切面编程。

大白话版:

Spring AOP就像是在你的程序中悄悄安排了一位助手,它能在你执行某些关键操作(比如付款、登录)之前或之后,自动帮你完成额外的工作(比如记录日志、检查权限),而无需你每次都亲自去操作。

2、 为什么要使用AOP

  • 代码解耦:业务逻辑和横向关注点(如日志、安全)分离,业务代码更干净,只关注核心逻辑。
  • 代码重用:日志记录、安全检查等通用功能只需要编写一次,通过AOP应用到多个模块。
  • 功能修改方便:如果需要修改通用功能,只需在AOP切面中修改,无需触及业务逻辑代码。

3、 需要了解的关键词

  • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等。

  • 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。

  • 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。

  • 目标(Target):被通知对象。

  • 代理(Proxy):向目标对象应用通知之后创建的对象。

  • 切入点(PointCut):切面通知 执行的 “地点”的定义。

  • 连接点(JointPoint):与切入点匹配的执行点。

3.1、 代码示例

首先,我们有一个AccountService类,它包含一些业务逻辑方法:

public class AccountService {
    public void withdraw(int amount) {
        // 取款逻辑
        System.out.println("取款 " + amount + " 元");
    }

    public void deposit(int amount) {
        // 存款逻辑
        System.out.println("存款 " + amount + " 元");
    }
}

现在,我们需要为withdrawdeposit方法添加日志记录功能。

横切关注点(Cross-Cutting Concern)

横切关注点是与业务逻辑无关,但需要在多个模块中执行的功能,比如日志记录:

java

复制

// 这是一个横切关注点,它与AccountService的业务逻辑无关
public void logMethodAccess(String methodName) {
    System.out.println("方法 " + methodName + " 被访问");
}

切面(Aspect)

切面是一个类,它将横切关注点模块化:

// 这是一个切面类
public aspect LoggingAspect {
    // ...
}

通知(Advice)

通知是切面类中的一个方法,它定义了横切关注点的具体行为:

public aspect LoggingAspect {
    // 这是一个前置通知,在目标方法执行前执行
    before(): execution(* AccountService.*(..)) {
        logMethodAccess(thisJoinPoint.getSignature().getName());
    }
}

目标(Target)

目标是被通知的对象,也就是我们的AccountService类:

public class AccountService {
    // ...
}

代理(Proxy)

代理是Spring AOP自动创建的对象,它将通知应用到目标对象上:

// 假设这是Spring自动生成的代理对象
public class AccountServiceProxy {
    private AccountService target;

    public void withdraw(int amount) {
        // 在调用目标方法之前,先执行通知(日志记录)
        logMethodAccess("withdraw");
        target.withdraw(amount);
    }

    public void deposit(int amount) {
        // 在调用目标方法之前,先执行通知(日志记录)
        logMethodAccess("deposit");
        target.deposit(amount);
    }
}

切入点(PointCut)

切入点定义了通知应该在哪里执行,这里是所有AccountService类的方法:

public aspect LoggingAspect {
    // 切入点定义
    pointcut allMethodsInAccountService(): execution(* AccountService.*(..));

    before(): allMethodsInAccountService() {
        logMethodAccess(thisJoinPoint.getSignature().getName());
    }
}

连接点(JointPoint)

连接点是实际执行通知的具体位置,在这个例子中,withdrawdeposit方法的每次调用都是一个连接点:

// 当withdraw方法被调用时,这里就是一个连接点
public void withdraw(int amount) {
    // ...
}

// 当deposit方法被调用时,这里也是一个连接点
public void deposit(int amount) {
    // ...
}

在这个例子中,每次调用AccountService的方法时,LoggingAspectbefore通知都会被执行,从而实现了日志记录的横切关注点。这个日志记录的行为是被自动添加到withdrawdeposit方法中的,而不需要修改这两个方法的原始代码。

4、 使用Spring实现Aop

        4.1 第一种方式:通过 Spring API 实现

首先编写我们的业务接口和实现类

public interface UserService {

   public void add();

   public void delete();

   public void update();

   public void search();

}
public class UserServiceImpl implements UserService{

   @Override
   public void add() {
       System.out.println("增加用户");
  }

   @Override
   public void delete() {
       System.out.println("删除用户");
  }

   @Override
   public void update() {
       System.out.println("更新用户");
  }

   @Override
   public void search() {
       System.out.println("查询用户");
  }
}

然后去写我们的增强类 , 我们编写两个 , 一个前置增强 一个后置增强

public class Log implements MethodBeforeAdvice {

   //method : 要执行的目标对象的方法
   //objects : 被调用的方法的参数
   //Object : 目标对象
   @Override
   public void before(Method method, Object[] objects, Object o) throws Throwable {
       System.out.println( o.getClass().getName() + "的" + method.getName() + "方法被执行了");
  }
}
public class AfterLog implements AfterReturningAdvice {
   //returnValue 返回值
   //method被调用的方法
   //args 被调用的方法的对象的参数
   //target 被调用的目标对象
   @Override
   public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
       System.out.println("执行了" + target.getClass().getName()
       +"的"+method.getName()+"方法,"
       +"返回值:"+returnValue);
  }
}

最后去spring的文件中注册 , 并实现aop切入实现 , 注意导入约束 .

   <!--注册bean-->
   <bean id="userService" class="com.kuang.service.UserServiceImpl"/>
   <bean id="log" class="com.kuang.log.Log"/>
   <bean id="afterLog" class="com.kuang.log.AfterLog"/>

   <!--aop的配置-->
   <aop:config>
       <!--切入点 expression:表达式匹配要执行的方法-->
       <aop:pointcut id="pointcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
       <!--执行环绕; advice-ref执行方法 . pointcut-ref切入点-->
       <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
       <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
   </aop:config>

        

4.2第二种方式: 自定义类来实现Aop

目标业务类不变依旧是userServiceImpl

第一步 : 写我们自己的一个切入类

public class DiyPointcut {

   public void before(){
       System.out.println("---------方法执行前---------");
  }
   public void after(){
       System.out.println("---------方法执行后---------");
  }
   
}

去spring中配置

<!--第二种方式自定义实现-->
<!--注册bean-->
<bean id="diy" class="com.kuang.config.DiyPointcut"/>

<!--aop的配置-->
<aop:config>
   <!--第二种方式:使用AOP的标签实现-->
   <aop:aspect ref="diy">
       <aop:pointcut id="diyPonitcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
       <aop:before pointcut-ref="diyPonitcut" method="before"/>
       <aop:after pointcut-ref="diyPonitcut" method="after"/>
   </aop:aspect>
</aop:config>

4.3 第三种方式: 使用注解实现

第一步:编写一个注解实现的增强类

@Aspect
public class AnnotationPointcut {
   @Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
   public void before(){
       System.out.println("---------方法执行前---------");
  }

   @After("execution(* com.kuang.service.UserServiceImpl.*(..))")
   public void after(){
       System.out.println("---------方法执行后---------");
  }

   @Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
   public void around(ProceedingJoinPoint jp) throws Throwable {
       System.out.println("环绕前");
       System.out.println("签名:"+jp.getSignature());
       //执行目标方法proceed
       Object proceed = jp.proceed();
       System.out.println("环绕后");
       System.out.println(proceed);
  }
}

第二步:在Spring配置文件中,注册bean,并增加支持注解的配置

<!--第三种方式:注解实现-->
<bean id="annotationPointcut" class="com.kuang.config.AnnotationPointcut"/>
<aop:aspectj-autoproxy/>

 参考资料:狂神说Spring07:AOP就这么简单 (qq.com)

Spring AOP——Spring 中面向切面编程 - SharpCJ - 博客园 (cnblogs.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值