Spring5.0源碼深度解析之SpringBean的Aop通知調用鏈源碼分析

SpringAOP原理探究

思考:springAOP底層運用了什麼設計模式?算法

生成代理類:代理設計模式、底層五個通知造成調用鏈採用:責任鏈設計模式spring

下面咱們回顧下SpringAop實現流程:設計模式

一、配置@EnableAspectJAutoProxy:開啓AOP權限ide

二、@Import(AspectJAutoProxyRegistrar.class):往IOC容器中注入SpringAOP切面類函數

三、registerAspectJAnnotationAutoProxyCreatorIfNecessary():註冊切面類源碼分析

四、AnnotationAwareAspectJAutoProxyCreator.class:註冊到IOC容器中,【AOP的入口】post

五、AnnotationAwareAspectJAutoProxyCreator:祖宗是BeanPostProcessor接口,而實現BeanPostProcessor接口後,當Spring加載這個Bean會在實例化前調用其後置處理器實現加強ui

六、postProcessAfterInitialization:後置處理器【AOP實現核心邏輯】this

####6.一、wrapIfNecessary()判斷該對象是否在AOP的掃包範圍內,真正建立代理類的地方lua

#########6.1.一、getAdvicesAndAdvisorsForBean建立代理對象包括獲取加強方法和根據獲取的加強進行代理

#########6.1.二、createAopProxy()判斷被代理類是否實現了接口,若是有實現了接口的化,是採用JDK動態代理,不然狀況下就使用CGLIB代理

####6.二、根據條件判斷使用JdkDynamicAopProxy或者JdkDynamicAopProxy方法實現代理

####6.三、最終執行目標方法的時候,就會進入到JdkDynamicAopProxy 的invoke方法或者JdkDynamicAopProxy的intercept方法

####6.五、底層使用集合存放使用通知,而後再使用責任鏈設計模式循環的調用

建立代理

咱們先來總結下JDK和CGLIB方式

  • 若是目標對象實現了接口,默認狀況下會採用JDK的動態代理實現AOP
  • 若是目標對象實現了接口,能夠強制使用CGLIB實現AOP
  • 若是目標對象沒有實現接口,必須採用CGLIB庫,Spring會自動在JDK動態代理和CGLIB之間轉換

JDK動態代理和CGLIB字節碼生成的區別?

JDK動態代理只能對實現了接口的類生成代理,而不能針對類。

CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法,由於是繼承,因此該類或者方法最好不要聲明爲final

獲取代理

1.JDK代理使用示例

public interface UserService {
    //目標方法
    public abstract void add();
}
public class UserServiceImpl implements UserService {
    /**
     * dynamic.proxy.UserService#add()
     */
    public void add() {
        System.out.println("add.......");
    }
}
public class MyInvocationHandler implements InvocationHandler {

    //目標對象
    private Object target;

    /**
     * 構造函數
     * @param target:目標對象
     */
    public MyInvocationHandler(Object target) {
        super();
        this.target = target;
    }

    /**
     * 執行目標對象的方法
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("-------------before-----------");
        Object result = method.invoke(target, args);
        System.out.println("-------------after------------");
        return result;
    }

    public Object getProxy(){
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                target.getClass().getInterfaces(),this);
    }
}
public class ProxyTest {
    public static void main(String[] args) {
        //實例化目標對象
        UserService userService = new UserServiceImpl();
        //實例化InvocationHandler
        MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);
        //根據目標對象生成代理對象
        UserService proxy = (UserService) invocationHandler.getProxy();
        //調用代理對象的方法
        proxy.add();
    }
}

輸出結果:

JdkProxy使用示例源碼分析

咱們再次回顧下JDK代理方式,在整個建立過程當中,對於InvocationHandler的建立是最爲核心的,在自定義的InvocationHandler中須要重寫三個函數

構造函數,將代理的對象傳入

invoke方法,此方法中實現了AOP加強的全部邏輯

getProxy方法,此方法千篇一概,可是必不可少。

那麼咱們看看Spring中的JDK代理實現是否是也是這麼作的呢?繼續以前的跟蹤,到達JdkDynamicAopProxy的getProxy方法。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    } else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    } else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) {
        Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));//若是循環遍歷找到須要代理的對象,則會進入到這裏建立代理
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        } else {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }
    } else {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }
}
protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {
    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)this.beanFactory, beanName, beanClass);
    }

    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.copyFrom(this);
    if (!proxyFactory.isProxyTargetClass()) {
        if (this.shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        } else {
            this.evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }

    Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    this.customizeProxyFactory(proxyFactory);
    proxyFactory.setFrozen(this.freezeProxy);
    if (this.advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    return proxyFactory.getProxy(this.getProxyClassLoader());
}

獲取了五個通知:

public Object getProxy(@Nullable ClassLoader classLoader) {
    return this.createAopProxy().getProxy(classLoader);
}

public Object getProxy(@Nullable ClassLoader classLoader) {
    if (logger.isDebugEnabled()) {
        logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
    }

    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
    this.findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

咱們能夠推斷出,在JdkDynamicAopProxy中必定會有個invoke函數,而且JdkDynamicAopProxy會把AOP的核心邏輯寫在裏面。咱們查看代碼發現確實是有invoke方法

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;
    TargetSource targetSource = this.advised.targetSource;
    Object target = null;

    Class var9;
    try {
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            Boolean var19 = this.equals(args[0]);
            return var19;
        }

        if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            Integer var18 = this.hashCode();
            return var18;
        }

        if (method.getDeclaringClass() != DecoratingProxy.class) {
            Object retVal;
            if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                retVal = AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
                return retVal;
            }
            //有時候目標對象內部的自我調用將沒法實施切面中的加強則須要經過此屬性暴露代理
            if (this.advised.exposeProxy) {
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }

            target = targetSource.getTarget();
            Class<?> targetClass = target != null ? target.getClass() : null;
            //獲取當前方法的攔截器鏈
           List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
            if (chain.isEmpty()) {
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                //若是沒有發現任何攔截器那麼直接調用切點方法
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            } else {
                //將攔截器封裝在ReflectiveMethodInvocation,以便於使用其proceed進行連接
                MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                //執行攔截器鏈
                retVal = invocation.proceed();
            }

            Class<?> returnType = method.getReturnType();
            //返回結果
            if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                retVal = proxy;
            } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
                throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);
            }

            Object var13 = retVal;
            return var13;
....
}

上面函數中主要是 建立了一個攔截器鏈,並使用ReflectiveMethodInvocation類進行了鏈的封裝,而在ReflectiveMethodInvocation類的proceed方法中是怎麼實現前置加強和後置加強

public Object proceed() throws Throwable {
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return this.invokeJoinpoint();
    } else {
        //獲取下一個須要執行的攔截器
        Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            //動態匹配
            InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
            //匹配則執行攔截器,不匹配不執行攔截器
            return dm.methodMatcher.matches(this.method, this.targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
        } else {
            //普通攔截,直接調用攔截器,將this做爲參數傳遞以保證當前實例中調用鏈的執行
            return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
        }
    }
}

proceed方法中,ReflectiveMethodInvocation中的主要職責是維護了連接調用的計數器,記錄當前調用連接的位置,以便鏈能夠有序的進行下去。

CGLIB使用示例源碼分析

public class EnhancerDemo {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(EnhancerDemo.class);
        enhancer.setCallback(new MethodInterceptorImpl());

        EnhancerDemo demo = (EnhancerDemo) enhancer.create();
        demo.test();
        System.out.println(demo);

    }

    private void test() {
        System.out.println("EnhancerDemo #test()....");
    }

    private static class MethodInterceptorImpl implements MethodInterceptor{

        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("------before invoke----"+method);
            Object result = methodProxy.invokeSuper(o, objects);
            System.out.println("-----after invoke------"+method);
            return result;
        }
    }
}

運行結果

生成的對象爲:com.xiaoxu.cglib.EnhancerDemo$$EnhancerByCGLIB$$c9092bbe@78e03bb5的實例,這個類是運行時由CGLIB產生的。

咱們看下Spring源碼對CGLIB的實現:

public Object getProxy(@Nullable ClassLoader classLoader) {
    if (logger.isDebugEnabled()) {
        logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
    }

    try {
        Class<?> rootClass = this.advised.getTargetClass();
        Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
        Class<?> proxySuperClass = rootClass;
        int x;
        if (ClassUtils.isCglibProxyClass(rootClass)) {
            proxySuperClass = rootClass.getSuperclass();
            Class<?>[] additionalInterfaces = rootClass.getInterfaces();
            Class[] var5 = additionalInterfaces;
            int var6 = additionalInterfaces.length;

            for(x = 0; x < var6; ++x) {
                Class<?> additionalInterface = var5[x];
                this.advised.addInterface(additionalInterface);
            }
        }
        //驗證class
        this.validateClassIfNecessary(proxySuperClass, classLoader);
        //建立及配置Enhancer 
        Enhancer enhancer = this.createEnhancer();
        if (classLoader != null) {
            enhancer.setClassLoader(classLoader);
            if (classLoader instanceof SmartClassLoader && ((SmartClassLoader)classLoader).isClassReloadable(proxySuperClass)) {
                enhancer.setUseCache(false);
            }
        }

        enhancer.setSuperclass(proxySuperClass);
        enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
        enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
        enhancer.setStrategy(new CglibAopProxy.ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
        //設置攔截器
        Callback[] callbacks = this.getCallbacks(rootClass);
        Class<?>[] types = new Class[callbacks.length];

        for(x = 0; x < types.length; ++x) {
            types[x] = callbacks[x].getClass();
        }

        enhancer.setCallbackFilter(new CglibAopProxy.ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
        enhancer.setCallbackTypes(types);
        return this.createProxyClassAndInstance(enhancer, callbacks);
    } catch (IllegalArgumentException | CodeGenerationException var9) {
        throw new AopConfigException("Could not generate CGLIB subclass of class [" + this.advised.getTargetClass() + "]: Common causes of this problem include using a final class or a non-visible class", var9);
    } catch (Throwable var10) {
        throw new AopConfigException("Unexpected AOP exception", var10);
    }
}

這裏最重要的是經過getCallbacks方法設置攔截器鏈

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
    //對屬性expose-proxy處理
    boolean exposeProxy = this.advised.isExposeProxy();
    boolean isFrozen = this.advised.isFrozen();
    boolean isStatic = this.advised.getTargetSource().isStatic();
    //將攔截器封裝在DynamicAdvisedInterceptor中
    Callback aopInterceptor = new CglibAopProxy.DynamicAdvisedInterceptor(this.advised);
    Object targetInterceptor;
    if (exposeProxy) {
        targetInterceptor = isStatic ? new CglibAopProxy.StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) : new CglibAopProxy.DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
    } else {
        targetInterceptor = isStatic ? new CglibAopProxy.StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) : new CglibAopProxy.DynamicUnadvisedInterceptor(this.advised.getTargetSource());
    }

    Callback targetDispatcher = isStatic ? new CglibAopProxy.StaticDispatcher(this.advised.getTargetSource().getTarget()) : new CglibAopProxy.SerializableNoOp();
    Callback[] mainCallbacks = new Callback[]{aopInterceptor, (Callback)targetInterceptor, new CglibAopProxy.SerializableNoOp(), (Callback)targetDispatcher, this.advisedDispatcher, new CglibAopProxy.EqualsInterceptor(this.advised), new CglibAopProxy.HashCodeInterceptor(this.advised)};
    Callback[] callbacks;
    if (isStatic && isFrozen) {
        Method[] methods = rootClass.getMethods();
        Callback[] fixedCallbacks = new Callback[methods.length];
        this.fixedInterceptorMap = new HashMap(methods.length);

        for(int x = 0; x < methods.length; ++x) {
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
            fixedCallbacks[x] = new CglibAopProxy.FixedChainStaticTargetInterceptor(chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
            this.fixedInterceptorMap.put(methods[x].toString(), x);
        }
        //將攔截器加入到Callback中
        callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
        System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
        System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
        this.fixedInterceptorOffset = mainCallbacks.length;
    } else {
        callbacks = mainCallbacks;
    }
    return callbacks;
}

getCallbacks中spring考慮了不少狀況,可是對於咱們來講,只須要理解最經常使用的就能夠了,CGLIB中對於方法的攔截是經過將自定義的攔截器(實現MethodInterceptor接口)加入到Callback中

並在調用代理時直接激活攔截器中的intercept方法來實現。由此可推斷,對於CGLIB方式實現的代理,其核心邏輯必然在DynamicAdvisedInterceptor中的intercept中。

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;
    Object target = null;
    TargetSource targetSource = this.advised.getTargetSource();

    Object var16;
    try {
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
        target = targetSource.getTarget();
        Class<?> targetClass = target != null ? target.getClass() : null;
        //獲取攔截器鏈
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
             //若是攔截器鏈爲空則直接激活源原方法
            retVal = methodProxy.invoke(target, argsToUse);
        } else {
            //進入鏈
            retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();
        }
        retVal = CglibAopProxy.processReturnType(proxy, target, method, retVal);
        var16 = retVal;
    } finally {
        if (target != null && !targetSource.isStatic()) {
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            AopContext.setCurrentProxy(oldProxy);
        }
    }
    return var16;
}

上述的實現與JDK方式實現代理中的invoke方法大同小異,首先是構造鏈,而後封裝此鏈進行串聯調用,區別在於JDK中直接構造ReflectiveMethodInvocation,而在CGLIB中使用CglibMethodInvocation.

CglibMethodInvocation繼承自ReflectiveMethodInvocation,可是process方法並無重寫。

SpringBean的AOP

主要靠的是後置處理器BeanPostProcessor:在Bean對象初始化先後作一些加強

AnnotationAwareAspectJAutoProxyCreator的祖宗是BeanPostProcessor

純手寫SpringAop調用鏈思路

【0】環繞通知以前執行→【1】前置通知→目標方法→【2】後置通知→【3】環繞通知以後執行

責任鏈設計模式,底層經過遞歸算法+責任鏈

如何存放起來:使用集合存放這些通知,集合當中不存放咱們的方法,只存放鏈,那麼如何插入咱們的目標方法?

純手寫SpringAop調用鏈

public interface MethodInterceptor {
    /**
     * 定義共同通知骨架
     */
    public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException;
}
public class BeforMethodInterceptor implements MethodInterceptor {
    public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException {
        System.out.println(">>>>前置通知<<<<");
      // 執行咱們的目標方法
        methodInvocation.process();// 遞歸調用
    }
}
public class AfterMethodInterceptor implements MethodInterceptor {
    public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException {
        // 執行咱們的前置通知
        methodInvocation.process();
        System.out.println(">>>後置通知<<<");
    }
}
public class AroundMethodInterceptor implements MethodInterceptor {
    public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException {
        System.out.println("環繞通知在目標方法以前執行..");
        methodInvocation.process();
        System.out.println("環繞通知在目標方法以後執行..");
    }
}
public class UserService {
    public void login(String userName, Integer age) {
        System.out.println("userName:" + userName + ",age:" + age);
    }
}

MethodInvocation 可以把鏈串起來

public interface MethodInvocation {
    //調用鏈造成
    public void process() throws InvocationTargetException, IllegalAccessException;

}
public class DefaultMethodInvacation implements MethodInvocation {
    /**
     * 存放全部的通知
     */
    private List<MethodInterceptor> listMethodInterceptor;
    private Object target;// 目標對象
    private Method method;// 目標方法
    private Object args[];// 目標參數
    // 最終使用反射機制執行目標方法
    private int index;// 記錄當前鏈調用的位置
    public DefaultMethodInvacation(List<MethodInterceptor> listMethodInterceptor, Object target, Method method, Object[] args) {
        this.listMethodInterceptor = listMethodInterceptor;
        this.target = target;
        this.method = method;
        this.args = args;
    }
    /**
     * 調用鏈造成
     */
    @Override
    public void process() throws InvocationTargetException, IllegalAccessException {
        if (index == listMethodInterceptor.size()) {
            method.invoke(target, args); // 執行目標
            return;
        }
        MethodInterceptor methodInterceptor = listMethodInterceptor.get(index++);
        methodInterceptor.invoke(this);
    }
}

執行結果:

>>>>前置通知<<<<
環繞通知在目標方法以前執行..
userName:mayikt,age:12
環繞通知在目標方法以後執行..
>>>後置通知<<<

本文參考

參考書籍:Spring源碼深度解析

螞蟻課堂:http://www.mayikt.com/

相關文章
相關標籤/搜索