AOP面向切面编程简单总结

本文详细介绍了Spring AOP中的动态代理机制,包括JDK和Cglib代理的使用场景。同时,讲解了@Before、@After、@AfterThrowing、@AfterReturning和@Around等通知类型的实现及应用场景。还深入探讨了JointPoint和ProceedingJoinPoint的区别,并提供了完整的切面示例,展示了如何结合自定义注解进行AOP实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、切面的几种示例:

Spring AOP 其实就是使用动态代理来对切面层进行统一的处理。
动态代理的方式有:JDK动态代理和 cglib 动态代理,
JDK 动态代理:基于接口实现,要求目标类必须实现接口。
cglib 动态代理:用第三方的工具库创建代理对象。基于子类实现。原理是继承。通过继承目标类,创建子类,子类就是代理对象。要求目标类不能是final的,方法也不能是final的。
spring默认使用的是JDK动态代理,如果没有接口,spring会自动的使用cglib动态代理。

注:有一点非常重要,Spring的AOP只能支持到方法级别的切入。换句话说,切入点只能是某个方法。

1)@Before--前置切面

@Aspect
@Component
public class MyAspect {
    @Before("execution(* com.baizhi.service.*.*(..))")
    public void before(JoinPoint joinPoint){
        System.out.println("前置通知");
        joinPoint.getTarget();//目标对象
        joinPoint.getSignature();//方法签名
        joinPoint.getArgs();//方法参数
    }
}


2)@AfterThrowing
3)@After--后置切面

@Aspect
@Component
public class MyAspect {
    @After("execution(* com.baizhi.service.*.*(..))")
    public void before(JoinPoint joinPoint){
        System.out.println("后置通知");
        joinPoint.getTarget();//目标对象
        joinPoint.getSignature();//方法签名
        joinPoint.getArgs();//方法参数
    }
}

 4)@AfterReturning
 5)@Around--环绕切面。有返回值,

@Aspect
@Component
public class MyAspect {
    @Around("execution(* com.baizhi.service.*.*(..))")
    public Object before(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("进入环绕通知");
        proceedingJoinPoint.getTarget();//目标对象
        proceedingJoinPoint.getSignature();//方法签名
        proceedingJoinPoint.getArgs();//方法参数
        Object proceed = proceedingJoinPoint.proceed();//放行执行目标方法
        System.out.println("目标方法执行之后回到环绕通知");
        return proceed;//返回目标方法返回值
    }
}
注意: 前置通知和后置通知都没有返回值,方法参数都为joinpoint
注意: 环绕通知存在返回值,参数为ProceedingJoinPoint,如果执行放行,不会执行目标方法,一旦放行必须将目标方法的返回值返回,否则调用者无法接受返回数据

 二、JointPoint和ProceedingJoinPoint区别

每个切面类中的通知方法都会绑定一个切入点,这个切入点在执行时会被切面类的通知方法在所定义的时间点拦截,此时将优先执行该通知内的逻辑。而这个切入点对应的方法将会把一些信息传入JointPoint中。

1、JointPoint包含以下属性

# 返回目标对象,即被代理的对象。(切入点方法所在的类)
Object getTarget();

# 返回切入点的参数(方法上的形参)
Object[] getArgs();

# 返回切入点的Signature
Signature getSignature();

# 返回切入的类型,比如method-call,field-get等等,使用比较少
 String getKind();

2、ProceedingJoinPoint继承了 JoinPoint

是在JoinPoint的基础上暴露出 proceed 这个方法。ProceedingJoinPoint 用于环绕通知。

3、通过切入点操作目标对象(切入点所在类)


//--获取目标对象,即被代理的对象。(切入点所在的类)
  Object targetObj =joinPoint.getTarget();
//--1、可以发挥反射的功能获取关于类的任何信息,例如获取类名如下
  String className = joinPoint.getTarget().getClass().getName();
//--2、获取目标对象方法名,(切入点的方法名)
  String methodName = joinPoint.getSignature().getName();

4、通过切入点获取目标对象,再通过反射获取注解信息

        //切入点所在类(目标对象)
        Object target = joinPoint.getTarget();
        //切入点的方法名。
        String methodName = joinPoint.getSignature().getName();
 
        Method method = null;
        //通过反射获取类中的方法
        for (Method m : target.getClass().getMethods()) {
            if (m.getName().equals(methodName)) {
                method = m;
               //  xxxxxx annoObj= method.getAnnotation(xxxxxx.class);获取注解
                break;
            }
        }

5、通过joinPoint.getSignature获取切入点的方法

        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();//切入点的方法

        if (method != null)
        {
            xxxxxx annoObj= method.getAnnotation(xxxxxx.class);
        }
        return null;

6、获取切入点方法的参数

Object[] args = joinPoint.getArgs();//返回是一个数组,参数列表

 三、完整示例

切面一般时配合自定义注解使用。以下示例仅为简单使用。

1、引入依赖

 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-aop</artifactId>
 </dependency>

1、创建一个接口

    @RequestMapping("/add")
    public String addController(){
        //我是一个接口
        System.out.println("xxx在增加");
        System.out.println("增加成功");
        return "yes";
    }

2、创建切面类

package com.xhy.aop;
 
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
//标识为切面类
@Aspect
//类不被识别,将类变成一个组件
@Component
@Slf4j
 
public class LogAop {
//    指定切入的规则,".."代表可有参可无参
    @Pointcut("execution(* com.lv.controller.*Controller.*(..))")
    public  void logger(){}
 
//    环绕通知
    @Around("logger()")
    public void around(ProceedingJoinPoint point){
       
         //执行逻辑
 
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值