【学习笔记】Spring AOP

3 篇文章 0 订阅
2 篇文章 0 订阅


1. 基于注解的Demo:
package demo.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * @author xiesq
 * @version 1.0
 * @date 2021/3/22 23:45
 */
@Slf4j
@Component
@Aspect
public class LogAspect {

    /**
     * 切点 - 目标方法的匹配规则
     * public void 包名.类名.方法名(..)
     * *表示匹配所有字符串
     * ..表示子孙包下 或 任意个参数的method
     * 取反:!execution()
     * 多个匹配规则可用 ||、&&、or、and连接:execution() and execution()
     */
    @Pointcut("execution(public * demo.aop.service.UserServiceImpl.*(..))")
    public void pointCut(){
        //示例:
        //1.方法匹配:拦截目标类下的任意方法
        // execution(* demo.aop.service.UserServiceImpl.*(..))
        //拦截目标类下的任意public方法
        // execution(public * demo.aop.service.UserServiceImpl.*(..))
        //拦截目标类下的任意public,且以add开头的方法
        // execution(public * demo.aop.service.UserServiceImpl.add*(..))
        //拦截目标类下的任意public,且返回类型为String的方法
        // execution(public String demo.aop.service.UserServiceImpl.*(..))
        //拦截目标类下的任意public,且返回类型为String的,delete方法
        // execution(public String demo.aop.service.UserServiceImpl.delete())

        //2.包匹配:拦截指定包下的所有类下的所有方法
        // execution(* demo.aop.service.*.*(..)) demo.aop.service.所有类.所有方法(任意参数)
        // execution(* demo.aop.*.*.*(..))       demo.aop.所有子包.所有类.所有方法(任意参数)
        // execution(* demo.aop..*.*(..))        demo.aop.所有子孙包.所有类.所有方法(任意参数)

        //3.子级匹配:
        // execution(* demo.aop.service.BaseService+.*(..))  BaseService的子类.所有方法(任意参数)

        //4.注解匹配:
        // @annotation(com.demo.MyAnnotation)
    }

    /**
     * 前置增强
     * joinPoint - 切点:目标方法
     */
    @Before(value = "pointCut()")
    public void before(JoinPoint joinPoint){
        //joinPoint.getTarget(); 获取被代理对象
        //joinPoint.getThis();   获取代理对象
        //joinPoint.getSignature(); 获取方法签名(方法名、方法所属的类名等)
        //joinPoint.getArgs();   获取方法的参数
        log.info("{}方法执行前", joinPoint.getSignature().getName());
    }

    /**
     * 后置返回增强
     * 可通过returning属性获取到方法返回值
     */
    @AfterReturning(value = "pointCut()", returning = "result")
    public void afterReturning(Object result){
        log.info("方法执行后-afterReturning,返回值为:{}", result);
    }

    /**
     * 后置异常增强
     */
    @AfterThrowing(value = "pointCut()", throwing = "e")
    public void afterThrowing(Exception e){
        log.info("方法执行后-afterThrowing,exception:{}", e.getMessage());
    }

    /**
     * 后置finally增强
     */
    @After("pointCut()")
    public void after(){
        log.info("方法执行后");
    }

    /**
     * 环绕增强 - 通过jp.proceed()手动去执行目标方法,可在执行前、后、发生异常时编写增强代码
     * 环绕增强相当于包含了上面的所有增强功能,这里看实际需要,选择使用
     */
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint jp) {
        String methodName = jp.getSignature().getName();

        log.info("环绕增强:{}方法执行前", methodName);
        Object res = null;
        try {
            //调用执行目标方法
            res = jp.proceed();
        } catch (Throwable throwable) {
            log.error("环绕增强:执行方法时出错了:{}", throwable.getMessage());
            //此处 如果抛出异常将触发@AfterThrowing,如果不抛出异常则触发@AfterReturning
//            throwable.printStackTrace();
            throw new RuntimeException(throwable);
        }
        log.info("环绕增强:{}方法执行后", methodName);

        return res;
    }
}

2. 代理不生效的原因:
  • 动态生成的代理类ProxyServiceA是内部持有的一个被代理对象:
    public class ProxyServiceA implements ServiceA{
    	//内部持有一个被代理对象的实例
    	private ServiceA serviceA;
    	
    	public void methodA(){
       	//...前置增强
        serviceA.methodA();
       	//...后置增强
    	}
    
    	public void methodB(){
       	//...前置增强
        serviceA.methodB();
       	//...后置增强
    	}
    }
    
    
  • 当我们调用proxyServiceA.methodA()时,如果ServiceA#methodA()内部调用了this.methodB()的话,就相当于执行的是serviceA.methodB()而不是proxyServiceA.methodB(),那么methodB的增强逻辑将不会生效!
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值