天天看點

深入Spring源碼系列--Spring/Springboot 注解失效原因解析

Spring/Springboot 注解失效的原因解析

現象:Spring中某些注解失效事務失效的

原因:Spring進行AOP是維護的是代理對象,而第一調用代理對象中的方法,如果你在這個方法中直接調用該類中的另一個方,會導緻另一個方法的增強失敗,主要是由于第二調用是被代理對象去調用的。

失效代碼示例

調用add方法是會使得queryUser方法上的@Transactional失效

@Service
public class UserServiceImpl  {
    @Transactional
    public String queryUser(String userId) {
        System.out.println("UserServiceImpl1 ->" + userId);
        return "UserServiceImpl1 ->" + userId;
    }
    @Transactional
    public void add(String id) {
        queryUser(id);
        System.out.println("UserServiceImpl1 -> addxx");
    }
}
           

Spring的AOP是Spring一個重要組成部分,在Spring的實作用的是動态代理,Spring在對象執行個體化的過程中會根據執行個體的有切面進而對對象進行動态代理,具體的過程是在這個需要進行增強的Bean執行個體化完成後進行動态代理,具體的入口在AbstractAutowireCapableBeanFactory的applyBeanPostProcessorsAfterInitialization()

深入Spring源碼系列--Spring/Springboot 注解失效原因解析

該方法會周遊所有實作了BeanPostProcessor接口

進而會調用到AspectJwareAdvisorAutoProxyCreator(AbstractAutoProxyCreator)類中的postProcessBeforeInstantiation方法

深入Spring源碼系列--Spring/Springboot 注解失效原因解析

此方法調用到wrapIfNecessary()又會調用到getAdvicesAndAdvisorsForBean(),該方法主要是封裝所有切面對象,并且比對該類符合的切面然後進行傳回,

然後在wrapIfNecessary()中會建立代理對象,具體會調用到createProxy(),該方法首先會建立一個代理工廠,注意這個工廠是多執行個體的,一個beanClass對應一個代理工廠,這個代理工廠會封裝被代理對象以及這個被代理對象中所有的切面(這個劃重點,代理工廠中是存在被代理對象的!!!!),然後通過代理工廠建立代理對象。

深入Spring源碼系列--Spring/Springboot 注解失效原因解析
深入Spring源碼系列--Spring/Springboot 注解失效原因解析
深入Spring源碼系列--Spring/Springboot 注解失效原因解析

此時Spring會根據配置來構造是JdkDynamicAopProxy(jdk動态代理)還是生成ObjenesisCglibAopProxy(cglib代理),不管是哪一種均會把代理工廠封裝到兩種對象中,以jdkDynamicAopProxy為例:在調用getProxy方法是,就會傳回代理對象了。當用回調用代理對象時,回回調到JdkDynamicAopProxy的invoke()方法。

深入Spring源碼系列--Spring/Springboot 注解失效原因解析
深入Spring源碼系列--Spring/Springboot 注解失效原因解析

重點看invoke方法:在invoke方法主要關關注一下方法,第一個是判斷該方法是否存在切面,并且如何調用該方法的切面,Spring采用了一種過濾鍊的模式,剛才我們把代理工廠封裝到了jdkDynamicAopProxy對象中了,所有我們可以通過對象擷取到被代理對象所有的切面,然後用這些切面跟方法進行比對,比對成功的切面Spring就會把切面中的增強封裝成MethodInterceptor類型的對象,為什麼要封裝成MethodIntercepor對象呢,主要原因是由于增強的種類有五種,如果不封裝成統一類型對象,則會有大量的if-else判斷。上述過程主要在AdvisedSupport這個類中的getInterceptorsAndDynamicInterceptionAdvice()此方法中完成,找到了調用鍊後則會進行調用了。invoke()方法中會将目标對象目标對象方法目标方法參數封裝成ReflectiveMethodInvocation類型對象,調用該類型中的proceed()方法,再次方法中會是一個調用鍊的形式,進來先判斷切面方法是否執行完成,如果執行完成才會通過反射調用到目标對象的目标方法,注意此時的目标對象是被代理對象!!!

深入Spring源碼系列--Spring/Springboot 注解失效原因解析
深入Spring源碼系列--Spring/Springboot 注解失效原因解析
深入Spring源碼系列--Spring/Springboot 注解失效原因解析

通過對springAOP源碼的閱讀,我們就知道為什麼在同一個方法中,我們在其中一個方法調用另一個方法時會導緻另一個方法的注解失效。。。筆者通過自己寫的代碼将Spring的源碼的中生産的動态代理嘗試的類輸出到檔案中一下:

i

mport com.sun.proxy..Proxy50;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import org.aopalliance.aop.Advice;
import org.springframework.aop.Advisor;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.AopConfigException;

public final class userServiceProxy extends Proxy implements Proxy50 {
    private static Method m1;
    private static Method m31;
    private static Method m19;
    private static Method m24;
    private static Method m18;
    private static Method m14;
    private static Method m26;
    private static Method m32;
    private static Method m3;
    private static Method m21;
    private static Method m7;
    private static Method m6;
    private static Method m0;
    private static Method m28;
    private static Method m16;
    private static Method m23;
    private static Method m30;
    private static Method m34;
    private static Method m11;
    private static Method m2;
    private static Method m10;
    private static Method m12;
    private static Method m20;
    private static Method m13;
    private static Method m4;
    private static Method m5;
    private static Method m36;
    private static Method m9;
    private static Method m17;
    private static Method m38;
    private static Method m22;
    private static Method m33;
    private static Method m8;
    private static Method m37;
    private static Method m35;
    private static Method m27;
    private static Method m29;
    private static Method m25;
    private static Method m15;

    public userServiceProxy(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final InvocationHandler getInvocationHandler(Object var1) throws IllegalArgumentException {
        try {
            return (InvocationHandler)super.h.invoke(this, m31, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void addAdvisor(Advisor var1) throws AopConfigException {
        try {
            super.h.invoke(this, m19, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final boolean isExposeProxy() throws  {
        try {
            return (Boolean)super.h.invoke(this, m24, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final boolean isProxyTargetClass() throws  {
        try {
            return (Boolean)super.h.invoke(this, m18, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void removeAdvisor(int var1) throws AopConfigException {
        try {
            super.h.invoke(this, m14, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final Class[] getProxiedInterfaces() throws  {
        try {
            return (Class[])super.h.invoke(this, m26, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final Class getProxyClass(ClassLoader var1, Class[] var2) throws IllegalArgumentException {
        try {
            return (Class)super.h.invoke(this, m32, new Object[]{var1, var2});
        } catch (RuntimeException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    public final int indexOf(Advisor var1) throws  {
        try {
            return (Integer)super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final TargetSource getTargetSource() throws  {
        try {
            return (TargetSource)super.h.invoke(this, m21, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void addAdvice(int var1, Advice var2) throws AopConfigException {
        try {
            super.h.invoke(this, m7, new Object[]{var1, var2});
        } catch (RuntimeException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    public final void addAdvice(Advice var1) throws AopConfigException {
        try {
            super.h.invoke(this, m6, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final boolean isInterfaceProxied(Class var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m28, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final boolean removeAdvice(Advice var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m16, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void setExposeProxy(boolean var1) throws  {
        try {
            super.h.invoke(this, m23, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final Object newProxyInstance(ClassLoader var1, Class[] var2, InvocationHandler var3) throws IllegalArgumentException {
        try {
            return (Object)super.h.invoke(this, m30, new Object[]{var1, var2, var3});
        } catch (RuntimeException | Error var5) {
            throw var5;
        } catch (Throwable var6) {
            throw new UndeclaredThrowableException(var6);
        }
    }

    public final void wait(long var1, int var3) throws InterruptedException {
        try {
            super.h.invoke(this, m34, new Object[]{var1, var3});
        } catch (RuntimeException | InterruptedException | Error var5) {
            throw var5;
        } catch (Throwable var6) {
            throw new UndeclaredThrowableException(var6);
        }
    }

    public final void setTargetSource(TargetSource var1) throws  {
        try {
            super.h.invoke(this, m11, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final Class getTargetClass() throws  {
        try {
            return (Class)super.h.invoke(this, m10, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final Class getDecoratedClass() throws  {
        try {
            return (Class)super.h.invoke(this, m12, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void addAdvisor(int var1, Advisor var2) throws AopConfigException {
        try {
            super.h.invoke(this, m20, new Object[]{var1, var2});
        } catch (RuntimeException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    public final boolean removeAdvisor(Advisor var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m13, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final int indexOf(Advice var1) throws  {
        try {
            return (Integer)super.h.invoke(this, m4, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final boolean isFrozen() throws  {
        try {
            return (Boolean)super.h.invoke(this, m5, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final Class getClass() throws  {
        try {
            return (Class)super.h.invoke(this, m36, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void addxx(String var1) throws  {
        try {
            super.h.invoke(this, m9, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final boolean replaceAdvisor(Advisor var1, Advisor var2) throws AopConfigException {
        try {
            return (Boolean)super.h.invoke(this, m17, new Object[]{var1, var2});
        } catch (RuntimeException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    public final void notifyAll() throws  {
        try {
            super.h.invoke(this, m38, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void setPreFiltered(boolean var1) throws  {
        try {
            super.h.invoke(this, m22, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void wait() throws InterruptedException {
        try {
            super.h.invoke(this, m33, (Object[])null);
        } catch (RuntimeException | InterruptedException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String queryUser(String var1) throws  {
        try {
            return (String)super.h.invoke(this, m8, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void notify() throws  {
        try {
            super.h.invoke(this, m37, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void wait(long var1) throws InterruptedException {
        try {
            super.h.invoke(this, m35, new Object[]{var1});
        } catch (RuntimeException | InterruptedException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    public final String toProxyConfigString() throws  {
        try {
            return (String)super.h.invoke(this, m27, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final boolean isProxyClass(Class var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m29, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final Advisor[] getAdvisors() throws  {
        try {
            return (Advisor[])super.h.invoke(this, m25, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final boolean isPreFiltered() throws  {
        try {
            return (Boolean)super.h.invoke(this, m15, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m31 = Class.forName("com.sun.proxy.$Proxy50").getMethod("getInvocationHandler", Class.forName("java.lang.Object"));
            m19 = Class.forName("com.sun.proxy.$Proxy50").getMethod("addAdvisor", Class.forName("org.springframework.aop.Advisor"));
            m24 = Class.forName("com.sun.proxy.$Proxy50").getMethod("isExposeProxy");
            m18 = Class.forName("com.sun.proxy.$Proxy50").getMethod("isProxyTargetClass");
            m14 = Class.forName("com.sun.proxy.$Proxy50").getMethod("removeAdvisor", Integer.TYPE);
            m26 = Class.forName("com.sun.proxy.$Proxy50").getMethod("getProxiedInterfaces");
            m32 = Class.forName("com.sun.proxy.$Proxy50").getMethod("getProxyClass", Class.forName("java.lang.ClassLoader"), Class.forName("[Ljava.lang.Class;"));
            m3 = Class.forName("com.sun.proxy.$Proxy50").getMethod("indexOf", Class.forName("org.springframework.aop.Advisor"));
            m21 = Class.forName("com.sun.proxy.$Proxy50").getMethod("getTargetSource");
            m7 = Class.forName("com.sun.proxy.$Proxy50").getMethod("addAdvice", Integer.TYPE, Class.forName("org.aopalliance.aop.Advice"));
            m6 = Class.forName("com.sun.proxy.$Proxy50").getMethod("addAdvice", Class.forName("org.aopalliance.aop.Advice"));
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m28 = Class.forName("com.sun.proxy.$Proxy50").getMethod("isInterfaceProxied", Class.forName("java.lang.Class"));
            m16 = Class.forName("com.sun.proxy.$Proxy50").getMethod("removeAdvice", Class.forName("org.aopalliance.aop.Advice"));
            m23 = Class.forName("com.sun.proxy.$Proxy50").getMethod("setExposeProxy", Boolean.TYPE);
            m30 = Class.forName("com.sun.proxy.$Proxy50").getMethod("newProxyInstance", Class.forName("java.lang.ClassLoader"), Class.forName("[Ljava.lang.Class;"), Class.forName("java.lang.reflect.InvocationHandler"));
            m34 = Class.forName("com.sun.proxy.$Proxy50").getMethod("wait", Long.TYPE, Integer.TYPE);
            m11 = Class.forName("com.sun.proxy.$Proxy50").getMethod("setTargetSource", Class.forName("org.springframework.aop.TargetSource"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m10 = Class.forName("com.sun.proxy.$Proxy50").getMethod("getTargetClass");
            m12 = Class.forName("com.sun.proxy.$Proxy50").getMethod("getDecoratedClass");
            m20 = Class.forName("com.sun.proxy.$Proxy50").getMethod("addAdvisor", Integer.TYPE, Class.forName("org.springframework.aop.Advisor"));
            m13 = Class.forName("com.sun.proxy.$Proxy50").getMethod("removeAdvisor", Class.forName("org.springframework.aop.Advisor"));
            m4 = Class.forName("com.sun.proxy.$Proxy50").getMethod("indexOf", Class.forName("org.aopalliance.aop.Advice"));
            m5 = Class.forName("com.sun.proxy.$Proxy50").getMethod("isFrozen");
            m36 = Class.forName("com.sun.proxy.$Proxy50").getMethod("getClass");
            m9 = Class.forName("com.sun.proxy.$Proxy50").getMethod("addxx", Class.forName("java.lang.String"));
            m17 = Class.forName("com.sun.proxy.$Proxy50").getMethod("replaceAdvisor", Class.forName("org.springframework.aop.Advisor"), Class.forName("org.springframework.aop.Advisor"));
            m38 = Class.forName("com.sun.proxy.$Proxy50").getMethod("notifyAll");
            m22 = Class.forName("com.sun.proxy.$Proxy50").getMethod("setPreFiltered", Boolean.TYPE);
            m33 = Class.forName("com.sun.proxy.$Proxy50").getMethod("wait");
            m8 = Class.forName("com.sun.proxy.$Proxy50").getMethod("queryUser", Class.forName("java.lang.String"));
            m37 = Class.forName("com.sun.proxy.$Proxy50").getMethod("notify");
            m35 = Class.forName("com.sun.proxy.$Proxy50").getMethod("wait", Long.TYPE);
            m27 = Class.forName("com.sun.proxy.$Proxy50").getMethod("toProxyConfigString");
            m29 = Class.forName("com.sun.proxy.$Proxy50").getMethod("isProxyClass", Class.forName("java.lang.Class"));
            m25 = Class.forName("com.sun.proxy.$Proxy50").getMethod("getAdvisors");
            m15 = Class.forName("com.sun.proxy.$Proxy50").getMethod("isPreFiltered");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
           

可以看到其實動态代理生産的類方法調用最後是調用到h.invoke()方法,h就是之前的JdkDynamicAopProxy類型的對象,h.invoke就是調用到前面我們所說的invoke方法,我們直接調用的方法的增強是生效的,但是你在方法内直接調用的該類中的其他方法中的增強是不生效的,原因是我們會調用到invoke中的 retVal=invocatin.proceed()方法,而該方法最終調用的是通過被代理對象去調用自己的方法及最終是執行method.invke(target,args)這個代碼,是以我們在目标方法直接調用本類中的另一個方法,會導緻注解失效。總結來說就由于我們最終使用使用原對象去調用,而非代理對象去調用,是以導緻增強失敗。解決方式很簡單,我們換成代理對象去調用就可以了。