面向切面编程(AOP)

        面向切面编程(AOP)是面向对象编程(OOP)的补充和完善。

核心知识点主要包括以下几个方面:

  1. 连接点(Joinpoint):程序执行过程中的一些点,比如方法调用,异常处理等。在AOP中,所有方法都被视为连接点,无论是接口里的抽象方法还是实现类里的重写方法。

  2. 切入点(Pointcut):可能被抽取共性功能的方法称为切入点。切入点是连接点的子集。

  3. 通知(Advice):将抽取出来的共性功能称为通知。它可以在方法的调用之前、之后或者抛出异常时执行。

  4. AOP代理:AOP实现的关键在于AOP框架自动创建的AOP代理,主要分为静态代理和动态代理。

  5. 切面(Apect):描述通知与切入点的对应关系(通知+切入点)

  6. 目标对象(Target):通知所作用的对象

通知类型:

  1. 环绕通知(@Around):环绕通知是最为强大的一种通知类型,可以在切入点方法的执行前后进行自定义操作。例如,可以进行权限校验、日志记录等功能。

  2. 前置通知(@Before):这种通知在切入点方法之前执行。它可以用于权限检查、日志记录等功能。

  3. 后置通知(@After):这种通知在切入点方法之后执行。常常用于资源清理、性能统计等功能。

  4. 返回通知(@AfterReturning):这种通知在切入点方法成功执行之后执行。常用于结果处理、缓存更新等场景。

  5. 异常通知(@AfterThrowing):在切入点方法抛出异常后执行。通常用于错误处理、事务回滚等操作。

注意事项:

  • @Around环绕通知需要自己调用 ProceedingJoinPoint.proceed() 来让原始方法执行,其他通知不需要考虑目标方法执行
  • @Around环绕通知方法的返回值,必须指定为Object,来接收原始方法的返回值。
@Slf4j
@Component
@Aspect
public class MyAspect1 {
    
    @Pointcut("execution(* com.itheima.service.impl.DeptServiceImpl.*(..))")
    private void pt(){}

    @Before("pt()")
    public void before() {
        log.info("before ...");
    }

    @Around("pt()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("around before...");

        //调用目标对象的原始方法执行
        Object result = proceedingJoinPoint.proceed();

        log.info("around after...");
        return result;
    }

    @After("pt()")
    public void after() {
        log.info("after ...");
    }

    @AfterReturning("pt()")
    public void afterReturning() {
        log.info("afterReturning ...");
    }

    @AfterThrowing("pt()")
    public void afterThrowing() {
        log.info("afterThrowing ...");
    }
}

 

@PointCut

该注解的作用是将公共的切点表达式抽取出来,需要时引用到该切点表达式即可

原始代码: 

@Slf4j
@Component
@Aspect
public class MyAspect1 {
    
    @Pointcut("execution(* com.itheima.service.impl.DeptServiceImpl.*(..))")
    private void pt(){}

    @Before("execution(* com.itheima.service.impl.DeptServiceImpl.*(..))")
    public void before() {
        log.info("before ...");
    }

    @Around("execution(* com.itheima.service.impl.DeptServiceImpl.*(..))")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("around before...");

        //调用目标对象的原始方法执行
        Object result = proceedingJoinPoint.proceed();

        log.info("around after...");
        return result;
    }

    @After("execution(* com.itheima.service.impl.DeptServiceImpl.*(..))")
    public void after() {
        log.info("after ...");
    }

    @AfterReturning("execution(* com.itheima.service.impl.DeptServiceImpl.*(..))")
    public void afterReturning() {
        log.info("afterReturning ...");
    }

    @AfterThrowing("execution(* com.itheima.service.impl.DeptServiceImpl.*(..))")
    public void afterThrowing() {
        log.info("afterThrowing ...");
    }

}

引入@PointCut后:

@Slf4j
@Component
@Aspect
public class MyAspect1 {

    @Pointcut("execution(* com.itheima.service.impl.DeptServiceImpl.*(..))")
    public void pt(){}

    @Before("pt()")
    public void before() {
        log.info("before ...");
    }

    @Around("pt()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("around before...");

        //调用目标对象的原始方法执行
        Object result = proceedingJoinPoint.proceed();

        log.info("around after...");
        return result;
    }

    @After("pt()")
    public void after() {
        log.info("after ...");
    }

    @AfterReturning("pt()")
    public void afterReturning() {
        log.info("afterReturning ...");
    }

    @AfterThrowing("pt()")
    public void afterThrowing() {
        log.info("afterThrowing ...");
    }
}

通知的执行顺序:

1.不同的切面类中,默认按照切面类的类名字母排序:
  • 目标方法前的通知方法:字母排名靠前的先执行
  • 目标方法后的通知方法:字母排名靠前的后执行

以上内容基本一致,只是改变输出序号:

  

2.用@Order(数字) 加在切面类上来控制顺序
  • 目标方法前的通知方法:数字小的先执行
  • 目标方法后的通知方法:数字小的后执行

加上这样的注解: 

切入点表达式: 

execution:主要跟据方法的返回值、包名、类名、方法名、方法参数等信息来匹配,语法为:

execution(修饰符? 返回类型 包名.类名.?方法名(参数列表) throws 异常?)

注意:带?的可以省略;

* :代表独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以是通配包、类、方法名的一部分

..  : 多个连续的任意符号,可以通配任意层级的包,或者任意类型、任意个数的参数

@annotation(注解全类名)

        在Java中,注解(Annotation)是一种用于为代码提供元数据的机制。它可以用于标记类、方法、字段等元素,以便在编译时或运行时进行额外的处理。 

案例: 

 

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyLog {
}
@Component
@Slf4j
@Aspect
public class MyAspect7 {
//    @Pointcut("execution(public void com.itheima.service.impl.DeptServiceImpl.delete(java.lang.Integer))")
   @Pointcut("@annotation(com.itheima.aop.MyLog)")
    private void pt(){}

    @Before("pt()")
    public void before(){
        log.info("MyAspect7 ... before ...");
    }
}

 运行结果:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值