[[Java动态代理]] [[Java注解与自定义注解]] [[Spring中利用AOP使用自定义注解]]

使用 @Transactional , @Async 等Spring AOP注解不生效

问题背景

public class ServiceImpl implements Service{
    // funA是接口暴露方法
    @Override
    public void funA(){
    	try{
        	funA();
        }catch(Exception e){
        	Logger.infor(e);
        }
    }
    // funB是接口暴露方法
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void funB(){
        // 执行计算逻辑
    	funC();
    }
    
    public void funC(){
    	insertIntoHeader();
        // 计算逻辑...
        try{
            // 计算出错
        }catch(Exception e){
            // 执行catch代码块
        	throw new CommonException("xxxx");
        }
        insertIntoLine();
    }
}

以上代码出现了header插入成功,但是计算出错导致line插入失败的结果,分析过后发现其实是调用的时候没有使用动态代理对象来调用funB()导致funB()上面的 @Transactional(rollbackFor = Exception.class) 失效,从而使得整个 funA->funB->funC 流程都没有被spring事务管理器管理起来。写到这里,就必须把spring的AOP机制原理以及spring的aop常见问题记录下来了:首先必须要记住的一个点就是spring的AOP是通过动态代理完成,其次就是spring aop注解失效以及解决方案。

解释说明

通常情况,会出现Spring AOP注解失效主要是因为在同一个类中,funA调用给了funB(funB上加有注解),此时注解不生效。 针对所有的Spring AOP注解,Spring在扫描bean的时候发现有AOP注解,那么会动态的构造一个代理对象

  1. 如果是想要通过类的对象(通过spring依赖注入)直接调用其中带注解的funA时,此时funA的注解生效,因为此时spring会使用类的代理对象调用funA
  2. 假设类中的funA调用带有AOP注解的funB,而我们是通过对象(通过Spring依赖注入)调用funA的,那么funB上的注解是不生效的,因为此时调用funB使用的是原对象,而非代理对象,那么A在调用B时,在原对象内funB的注解当然时无效的。

解决方案:

  1. 把两个方法放到不同的类中
  2. 通过获取当前动态代理对象调用funcB:((X)AopContext.currentProxy()).B()

springboot下的分布式锁执行顺序

  • 切面之间使用older注解,区分调用顺序,Order值越小,那么切面越先执行(越后结束)
  • 不指定Order,那么Order是默认值->Integer.MAX_VALUE. 如果Order相同,则是按照切面字母的顺序来执行切面.比如@Transactional和@Cacheable->对应的切面是TransactionInterceptor和CacheInterceptor,则先执行@Cacheable的切面
  • @Transactional也是通过切面实现,Order值是Integer.MAX_VALUE。(如果在service方法上同时添加带order的日志注解,在日志切面after里面报错,不会回滚事务)
@Target({ElementType.TYPE})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
@Import({TransactionManagementConfigurationSelector.class})  
public @interface EnableTransactionManagement {  
    boolean proxyTargetClass() default false;  
  
    AdviceMode mode() default AdviceMode.PROXY;  
  
    int order() default 2147483647;  
}