美文网首页spring framework
AopContext.currentProxy()解决同类中调用

AopContext.currentProxy()解决同类中调用

作者: markeNick | 来源:发表于2021-06-21 21:50 被阅读0次
    class Service {
        
        public void A() {
            // 调用本类其他方法,事务失效
            this.B();
        }
        
        @Transactional
        public void B() {
            
        }
    }
    

    如上代码,在同一个类中,非事务方法A调用事务方法B,会导致事务失效,可以采用AopContext.currentProxy().xxxxx()来保证事务生效。

    无法切入的原因:

    切入原理:创建代理类,在代理类中调用目标方法时进行切入。

    上面代码,此时目标对象service,代理对象是Proxy_0,在同类Service中A方法调用B,本质是 this.B(),而不是Proxy_0.B()

    其他解决办法

    • ApplicationContext.getBean()

    • 在本类中注入自己

    • 使用手动事务

    注意事项:

    Spring Boot需要在启动类加上以下注解

    @EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)

    SSM需要xml文件配置

    <aop:aspectj-autoproxy proxy-target-class="true"expose-proxy="true"/>

    为什么AopContext可以解决同类方法AOP失效问题

    AopContext类的源码如下

    package org.springframework.aop.framework;
    
    import org.springframework.core.NamedThreadLocal;
    import org.springframework.lang.Nullable;
    
    public final class AopContext {
    
        // 维护了一个ThreadLocal,存放AOP代理类
        private static final ThreadLocal<Object> currentProxy = new NamedThreadLocal<>("Current AOP proxy");
    
    
        private AopContext() {
        }
    
        public static Object currentProxy() throws IllegalStateException {
            Object proxy = currentProxy.get();
            if (proxy == null) {
                throw new IllegalStateException(
                        "Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available, and " +
                                "ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context.");
            }
            return proxy;
        }
    
        // 提供代理类set进ThreadLocal方法
        @Nullable
        static Object setCurrentProxy(@Nullable Object proxy) {
            Object old = currentProxy.get();
            if (proxy != null) {
                currentProxy.set(proxy);
            }
            else {
                currentProxy.remove();
            }
            return old;
        }
    
    }
    

    Spring中创建动态代理有两种方式

    • JDK动态代理

    • cglib动态代理

    jdk动态代理创建时JdkDynamicAopProxy中的invoke方法中调用AopContext存入代理类

    image-20210621154601726.png

    cglib动态代理CglibAopProxy在创建代理时也调用AopContext存入代理类


    image-20210621155326867.png

    相关文章

      网友评论

        本文标题:AopContext.currentProxy()解决同类中调用

        本文链接:https://www.haomeiwen.com/subject/udeuyltx.html