spring aop 切面执行顺序和常见问题

切面注解的执行顺序

public Object aop(Method method,Object object) {
    try {
        try {
            /*doAround start*/
            doBefore();
            method.invoke(object);
            /*doAround end*/
        } finally {
            doAfter();
        }
        doAfterReturning();
    } catch (Exception e) {
        doAfterThrowing();
    }
}

切面间的执行顺序

  • 切面之间使用older注解,区分调用顺序,Order值越小,那么切面越先执行(越后结束).

  • 不指定Order,那么Order是默认值->Integer.MAX_VALUE. 如果Order相同,则是按照切面字母的顺序来执行切面.比如@Transactional和@Cacheable->对应的切面是TransactionInterceptor和CacheInterceptor,则先执行@Cacheable的切面
  • @Transactional也是通过切面实现,Order值是Integer.MAX_VALUE。(如果在service方法上同时添加带older的日志注解,在日志切面after里面报错,不会回滚事务)

常见问题示例

1.方法A调用同类中的方法B,方法B上的切面不会生效

问题示例:
@Component

public class StrategyService extends BaseStrategyService  {

    public PricingResponse getFactor(Map<String, String> pricingParams) {

        // 做一些参数校验,以及异常捕获相关的事情

        return this.loadFactor(tieredPricingParams);

    }

    @Override

    @StrategyCache(keyName = "key0001", expireTime = 60 * 60 * 2)

    private PricingResponse loadFactor(Map<String, String> pricingParams) {

        //代码执行

    }

}

原因:Spring的AOP是通过代理对象调用,只有这种调用方式,才能够在真正的对象的执行前后,能够让代理对象也执行相关代码,才能起到切面的作用。而对于上面使用this的方式调用,这种只是自调用,并不会使用代理对象进行调用,也就无法执行切面类。

 public static void main(String[] args) {

        ProxyFactory factory = new ProxyFactory(new SimplePojo());

        factory.addInterface(Pojo.class);

        factory.addAdvice(new RetryAdvice());

        Pojo pojo = (Pojo) factory.getProxy();

        // this is a method call on the proxy!

        pojo.foo();

    }

解决方法:使用AopContext.currentProxy()获取到代理对象,然后通过代理对象调用对应的方法。还有个地方需要注意,以上方式还需要将Aspect的expose-proxy设置成true。

@Component

public class StrategyService{

    public PricingResponse getFactor(Map<String, String> pricingParams) {

        // 做一些参数校验,以及异常捕获相关的事情

        // 这里不使用this.loadFactor而是使用AopContext.currentProxy()调用,目的是解决AOP代理不支持方法自调用的问题

        if (AopContext.currentProxy() instanceof StrategyService) {

            return ((StrategyService)AopContext.currentProxy()).loadFactor(tieredPricingParams);

        } else {

            // 部分实现没有被代理过,则直接进行自调用即可

            return loadFactor(tieredPricingParams);

        }

    }

    @Override

    @StrategyCache(keyName = "key0001", expireTime = 60 * 60 * 2)

    private PricingResponse loadFactor(Map<String, String> oricingParams) {

        //代码执行

    }

}

//还有个地方需要注意,以上方式还需要将Aspect的expose-proxy设置成true。如果是配置文件修改:
 <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
//如果是SpringBoot,则修改应用启动入口类的注解:
@EnableAspectJAutoProxy(exposeProxy = true)

public class Application {

}


 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值