AOP設(shè)計原理

從JVM看aop

1. Java程序運行在JVM中的特征

當我們在某個類Foo中寫好了一個main()方法,然后執(zhí)行java Foo,你的Java程序之旅就開啟了,如下:

public class Foo {
    public static void main(String[] args) {
        // your codes begins here
    }
}

那么在這個執(zhí)行的過程中,JVM都為你干了什么呢?

當你執(zhí)行java Foo 的時候,JVM會創(chuàng)建一個主線程main,這個主線程以上述的main()方法作為入口,開始執(zhí)行你的代碼。每一個線程在內(nèi)存中都會維護一個屬于自己的棧(Stack),記錄著整個程序執(zhí)行的過程。棧里的每一個元素稱為棧幀(Stack Frame),棧幀表示著某個方法調(diào)用,會記錄方法調(diào)用的信息;實際上我們在代碼中調(diào)用一個方法的時候,在內(nèi)存中就對應(yīng)著一個棧幀的入棧和出棧。

在某個特定的時間點,一個Main線程內(nèi)的棧會呈現(xiàn)如下圖所示的情況:


image.png

2. Java程序執(zhí)行流 【了解AOP、連接點(Join Point)、切入點(point cut) 的概念 】

如果從虛擬機線程棧的角度考慮Java程序執(zhí)行的話,那么,你會發(fā)現(xiàn),真?zhèn)€程序運行的過程就是方法調(diào)用的過程。我們按照方法執(zhí)行的順序,將方法調(diào)用排成一串,這樣就構(gòu)成了Java程序流。
我們將上述的線程棧里的方法調(diào)用按照執(zhí)行流排列,會有如下類似的圖:


image.png

基于時間序列,我們可以將方法調(diào)用排成一條線。而每個方法調(diào)用則可以看成Java執(zhí)行流中的一個節(jié)點。這個節(jié)點在AOP的術(shù)語中,被稱為Join Point,即連接點。 一個Java程序的運行的過程,就是若干個連接點連接起來依次執(zhí)行的過程。

在我們正常的面向?qū)ο蟮乃季S中, 我們考慮的是如何按照時間序列通過方法調(diào)用來實現(xiàn)我們的業(yè)務(wù)邏輯。那么,什么是AOP(即面向切面的編程)呢?

通常面向?qū)ο蟮某绦?,代碼都是按照時間序列縱向展開的,而他們都有一個共性:即都是已方法調(diào)用作為基本執(zhí)行單位展開的。 將方法調(diào)用當做一個連接點,那么由連接點串起來的程序執(zhí)行流就是整個程序的執(zhí)行過程。

AOP(Aspect Oriented Programming)則是從另外一個角度來考慮整個程序的,AOP將每一個方法調(diào)用,即連接點作為編程的入口,針對方法調(diào)用進行編程。從執(zhí)行的邏輯上來看,相當于在之前縱向的按照時間軸執(zhí)行的程序橫向切入。相當于將之前的程序橫向切割成若干的面,即Aspect.每個面被稱為切面。
所以,根據(jù)我的理解,AOP本質(zhì)上是針對方法調(diào)用的編程思路。

image.png

既然AOP是針對切面進行的編程的,那么,你需要選擇哪些切面(即 連接點Joint Point)作為你的編程對象呢?

因為切面本質(zhì)上是每一個方法調(diào)用,選擇切面的過程實際上就是選擇方法的過程。那么,被選擇的切面(Aspect)在AOP術(shù)語里被稱為切入點(Point Cut). 切入點實際上也是從所有的連接點(Join point)挑選自己感興趣的連接點的過程。

image.png

既然AOP是針對方法調(diào)用(連接點)的編程, 現(xiàn)在又選取了你感興趣的自己感興趣的鏈接點---切入點(Point Cut)了,那么,AOP能對它做什么類型的編程呢?AOP能做什么呢?

了解這個之前,我們先要知道一個非常重要的問題: 既然AOP是對方法調(diào)用進行的編程,那么,AOP如何捕獲方法調(diào)用的呢? 弄清楚這個問題,你不得不了解設(shè)計模式中的代理模式了。下面我們先來了解一下引入了代理模式的Java程序執(zhí)行流是什么樣子的。

3. 引入了代理模式的Java程序執(zhí)行流(AOP實現(xiàn)的機制)

我們假設(shè)在我們的Java代碼里,都為實例對象通過代理模式創(chuàng)建了代理對象,訪問這些實例對象必須要通過代理,那么,加入了proxy對象的Java程序執(zhí)行流會變得稍微復(fù)雜起來。

我們來看下加入了proxy對象后,Java程序執(zhí)行流的示意圖:


image.png

加入了代理模式的Java程序執(zhí)行流,使得所有的方法調(diào)用都經(jīng)過了代理對象。對于Spring AOP框架而言,它負責(zé)控制著真?zhèn)€容器內(nèi)部的代理對象。當我們調(diào)用了某一個實例對象的任何一個非final的public方法時,整個Spring框架都會知曉。

此時的SpringAOP框架在某種程度上扮演著一個上帝的角色:它知道你在這個框架內(nèi)所做的任何操作,你對每一個實例對象的非final的public方法調(diào)用都可以被框架察覺到!

image.png

4. Spring AOP的工作原理

前面已經(jīng)介紹了AOP編程首先要選擇它感興趣的連接點----即切入點(Point cut),那么,AOP能對切入點做什么樣的編程呢? 我們先將代理模式下的某個連接點細化,你會看到如下這個示意圖所表示的過程:

image.png
image.png
image.png

5、Spring AOP的核心---ProxyFactoryBean

ProxyFactoryBean提供了如下信息:

1). Proxy應(yīng)該感興趣的Adivce列表;

2). 真正的實例對象引用ticketService;

3).告訴ProxyFactoryBean使用基于接口實現(xiàn)的JDK動態(tài)代理機制實現(xiàn)proxy:

4). Proxy應(yīng)該具備的Interface接口:TicketService;

根據(jù)這些信息,ProxyFactoryBean就能給我們提供我們想要的Proxy對象了!那么,ProxyFactoryBean幫我們做了什么?

image.png

Spring 使用工廠Bean模式創(chuàng)建每一個Proxy,對應(yīng)每一個不同的Class類型,在Spring中都會有一個相對應(yīng)的ProxyFactoryBean. 以下是ProxyFactoryBean的類圖。


image.png

如上所示,對于生成Proxy的工廠Bean而言,它要知道對其感興趣的Advice信息,而這類的信息,被維護到Advised中。Advised可以根據(jù)特定的類名和方法名返回對應(yīng)的AdviceChain,用以表示需要執(zhí)行的Advice串。

6、基于JDK面向接口的動態(tài)代理JdkDynamicAopProxy生成代理對象

JdkDynamicAopProxy類實現(xiàn)了AopProxy,能夠返回Proxy,并且,其自身也實現(xiàn)了InvocationHandler角色。也就是說,當我們使用proxy時,我們對proxy對象調(diào)用的方法,都最終被轉(zhuǎn)到這個類的invoke()方法中。

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
        //省略若干...
    /** Proxy的配置信息,這里主要提供Advisor列表,并用于返回AdviceChain */
    private final AdvisedSupport advised;
 
    /**
     * Construct a new JdkDynamicAopProxy for the given AOP configuration.
     * @param config the AOP configuration as AdvisedSupport object
     * @throws AopConfigException if the config is invalid. We try to throw an informative
     * exception in this case, rather than let a mysterious failure happen later.
     */
    public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
        Assert.notNull(config, "AdvisedSupport must not be null");
        if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
            throw new AopConfigException("No advisors and no TargetSource specified");
        }
        this.advised = config;
    }
 
 
    @Override
    public Object getProxy() {
        return getProxy(ClassUtils.getDefaultClassLoader());
    }
        //返回代理實例對象
    @Override
    public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
        }
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
                //這里的InvocationHandler設(shè)置成了當前實例對象,即對這個proxy調(diào)用的任何方法,都會調(diào)用這個類的invoke()方法
                //這里的invoke方法被調(diào)用,動態(tài)查找Advice列表,組成ReflectMethodInvocation
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }
    /**
     * 對當前proxy調(diào)用其上的任何方法,都將轉(zhuǎn)到這個方法上
         * Implementation of {@code InvocationHandler.invoke}.
     * <p>Callers will see exactly the exception thrown by the target,
     * unless a hook method throws an exception.
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInvocation invocation;
        Object oldProxy = null;
        boolean setProxyContext = false;
 
        TargetSource targetSource = this.advised.targetSource;
        Class<?> targetClass = null;
        Object target = null;
 
        try {
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                // The target does not implement the equals(Object) method itself.
                return equals(args[0]);
            }
            if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                // The target does not implement the hashCode() method itself.
                return hashCode();
            }
            if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                    method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                // Service invocations on ProxyConfig with the proxy config...
                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
            }
 
            Object retVal;
 
            if (this.advised.exposeProxy) {
                // Make invocation available if necessary.
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }
 
            // May be null. Get as late as possible to minimize the time we "own" the target,
            // in case it comes from a pool.
            target = targetSource.getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }
 
            // Get the interception chain for this method.獲取當前調(diào)用方法的攔截鏈
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
 
            // Check whether we have any advice. If we don't, we can fallback on direct
            // reflective invocation of the target, and avoid creating a MethodInvocation.
                        //如果沒有攔截鏈,則直接調(diào)用Joinpoint連接點的方法。
            if (chain.isEmpty()) {
                // We can skip creating a MethodInvocation: just invoke the target directly
                // Note that the final invoker must be an InvokerInterceptor so we know it does
                // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            }
            else {
                // We need to create a method invocation...
                                //根據(jù)給定的攔截鏈和方法調(diào)用信息,創(chuàng)建新的MethodInvocation對象,整個攔截鏈的工作邏輯都在這個ReflectiveMethodInvocation里 
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // Proceed to the joinpoint through the interceptor chain.
                retVal = invocation.proceed();
            }
 
            // Massage return value if necessary.
            Class<?> returnType = method.getReturnType();
            if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
                    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                // Special case: it returned "this" and the return type of the method
                // is type-compatible. Note that we can't help if the target sets
                // a reference to itself in another returned object.
                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);
            }
            return retVal;
        }
        finally {
            if (target != null && !targetSource.isStatic()) {
                // Must have come from TargetSource.
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                // Restore old proxy.
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }
}

7、基于Cglib子類繼承方式的動態(tài)代理CglibAopProxy生成代理對象

package org.springframework.aop.framework;
/**
 * CGLIB-based {@link AopProxy} implementation for the Spring AOP framework.
 *
 * <p>Formerly named {@code Cglib2AopProxy}, as of Spring 3.2, this class depends on
 * Spring's own internally repackaged version of CGLIB 3.</i>.
 */
@SuppressWarnings("serial")
class CglibAopProxy implements AopProxy, Serializable {
 
    // Constants for CGLIB callback array indices
    private static final int AOP_PROXY = 0;
    private static final int INVOKE_TARGET = 1;
    private static final int NO_OVERRIDE = 2;
    private static final int DISPATCH_TARGET = 3;
    private static final int DISPATCH_ADVISED = 4;
    private static final int INVOKE_EQUALS = 5;
    private static final int INVOKE_HASHCODE = 6;
 
 
    /** Logger available to subclasses; static to optimize serialization */
    protected static final Log logger = LogFactory.getLog(CglibAopProxy.class);
 
    /** Keeps track of the Classes that we have validated for final methods */
    private static final Map<Class<?>, Boolean> validatedClasses = new WeakHashMap<Class<?>, Boolean>();
 
 
    /** The configuration used to configure this proxy */
    protected final AdvisedSupport advised;
 
    protected Object[] constructorArgs;
 
    protected Class<?>[] constructorArgTypes;
 
    /** Dispatcher used for methods on Advised */
    private final transient AdvisedDispatcher advisedDispatcher;
 
    private transient Map<String, Integer> fixedInterceptorMap;
 
    private transient int fixedInterceptorOffset;
 
 
    /**
     * Create a new CglibAopProxy for the given AOP configuration.
     * @param config the AOP configuration as AdvisedSupport object
     * @throws AopConfigException if the config is invalid. We try to throw an informative
     * exception in this case, rather than let a mysterious failure happen later.
     */
    public CglibAopProxy(AdvisedSupport config) throws AopConfigException {
        Assert.notNull(config, "AdvisedSupport must not be null");
        if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
            throw new AopConfigException("No advisors and no TargetSource specified");
        }
        this.advised = config;
        this.advisedDispatcher = new AdvisedDispatcher(this.advised);
    }
 
    /**
     * Set constructor arguments to use for creating the proxy.
     * @param constructorArgs the constructor argument values
     * @param constructorArgTypes the constructor argument types
     */
    public void setConstructorArguments(Object[] constructorArgs, Class<?>[] constructorArgTypes) {
        if (constructorArgs == null || constructorArgTypes == null) {
            throw new IllegalArgumentException("Both 'constructorArgs' and 'constructorArgTypes' need to be specified");
        }
        if (constructorArgs.length != constructorArgTypes.length) {
            throw new IllegalArgumentException("Number of 'constructorArgs' (" + constructorArgs.length +
                    ") must match number of 'constructorArgTypes' (" + constructorArgTypes.length + ")");
        }
        this.constructorArgs = constructorArgs;
        this.constructorArgTypes = constructorArgTypes;
    }
 
 
    @Override
    public Object getProxy() {
        return getProxy(null);
    }
 
    @Override
    public Object getProxy(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;
            if (ClassUtils.isCglibProxyClass(rootClass)) {
                proxySuperClass = rootClass.getSuperclass();
                Class<?>[] additionalInterfaces = rootClass.getInterfaces();
                for (Class<?> additionalInterface : additionalInterfaces) {
                    this.advised.addInterface(additionalInterface);
                }
            }
 
            // Validate the class, writing log messages as necessary.
            validateClassIfNecessary(proxySuperClass, classLoader);
 
            // Configure CGLIB Enhancer...
            Enhancer enhancer = 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 ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
 
            Callback[] callbacks = getCallbacks(rootClass);
            Class<?>[] types = new Class<?>[callbacks.length];
            for (int x = 0; x < types.length; x++) {
                types[x] = callbacks[x].getClass();
            }
            // fixedInterceptorMap only populated at this point, after getCallbacks call above
            enhancer.setCallbackFilter(new ProxyCallbackFilter(
                    this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
            enhancer.setCallbackTypes(types);
 
            // Generate the proxy class and create a proxy instance.
            return createProxyClassAndInstance(enhancer, callbacks);
        }
        catch (CodeGenerationException ex) {
            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",
                    ex);
        }
        catch (IllegalArgumentException ex) {
            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",
                    ex);
        }
        catch (Exception ex) {
            // TargetSource.getTarget() failed
            throw new AopConfigException("Unexpected AOP exception", ex);
        }
    }
 
    protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
        enhancer.setInterceptDuringConstruction(false);
        enhancer.setCallbacks(callbacks);
        return (this.constructorArgs != null ?
                enhancer.create(this.constructorArgTypes, this.constructorArgs) :
                enhancer.create());
    }
 
    /**
     * Creates the CGLIB {@link Enhancer}. Subclasses may wish to override this to return a custom
     * {@link Enhancer} implementation.
     */
    protected Enhancer createEnhancer() {
        return new Enhancer();
    }
 
 
 
    private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
        // Parameters used for optimisation choices...
        boolean exposeProxy = this.advised.isExposeProxy();
        boolean isFrozen = this.advised.isFrozen();
        boolean isStatic = this.advised.getTargetSource().isStatic();
 
        // Choose an "aop" interceptor (used for AOP calls).
        Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
 
        // Choose a "straight to target" interceptor. (used for calls that are
        // unadvised but can return this). May be required to expose the proxy.
        Callback targetInterceptor;
        if (exposeProxy) {
            targetInterceptor = isStatic ?
                    new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
                    new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
        }
        else {
            targetInterceptor = isStatic ?
                    new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
                    new DynamicUnadvisedInterceptor(this.advised.getTargetSource());
        }
 
        // Choose a "direct to target" dispatcher (used for
        // unadvised calls to static targets that cannot return this).
        Callback targetDispatcher = isStatic ?
                new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();
 
        Callback[] mainCallbacks = new Callback[] {
                aopInterceptor,  // for normal advice
                targetInterceptor,  // invoke target without considering advice, if optimized
                new SerializableNoOp(),  // no override for methods mapped to this
                targetDispatcher, this.advisedDispatcher,
                new EqualsInterceptor(this.advised),
                new HashCodeInterceptor(this.advised)
        };
 
        Callback[] callbacks;
 
        // If the target is a static one and the advice chain is frozen,
        // then we can make some optimisations by sending the AOP calls
        // direct to the target using the fixed chain for that method.
        if (isStatic && isFrozen) {
            Method[] methods = rootClass.getMethods();
            Callback[] fixedCallbacks = new Callback[methods.length];
            this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);
 
            // TODO: small memory optimisation here (can skip creation for methods with no advice)
            for (int x = 0; x < methods.length; x++) {
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
                fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
                        chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
                this.fixedInterceptorMap.put(methods[x].toString(), x);
            }
 
            // Now copy both the callbacks from mainCallbacks
            // and fixedCallbacks into the callbacks array.
            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;
    }
 
 
    /**
     * General purpose AOP callback. Used when the target is dynamic or when the
     * proxy is not frozen.
     */
    private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
 
        private final AdvisedSupport advised;
 
        public DynamicAdvisedInterceptor(AdvisedSupport advised) {
            this.advised = advised;
        }
 
        @Override
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            Object oldProxy = null;
            boolean setProxyContext = false;
            Class<?> targetClass = null;
            Object target = null;
            try {
                if (this.advised.exposeProxy) {
                    // Make invocation available if necessary.
                    oldProxy = AopContext.setCurrentProxy(proxy);
                    setProxyContext = true;
                }
                // May be null. Get as late as possible to minimize the time we
                // "own" the target, in case it comes from a pool...
                target = getTarget();
                if (target != null) {
                    targetClass = target.getClass();
                }
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                Object retVal;
                // Check whether we only have one InvokerInterceptor: that is,
                // no real advice, but just reflective invocation of the target.
                if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                    // We can skip creating a MethodInvocation: just invoke the target directly.
                    // Note that the final invoker must be an InvokerInterceptor, so we know
                    // it does nothing but a reflective operation on the target, and no hot
                    // swapping or fancy proxying.
                    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                    retVal = methodProxy.invoke(target, argsToUse);
                }
                else {
                    // We need to create a method invocation...
                    retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
                }
                retVal = processReturnType(proxy, target, method, retVal);
                return retVal;
            }
            finally {
                if (target != null) {
                    releaseTarget(target);
                }
                if (setProxyContext) {
                    // Restore old proxy.
                    AopContext.setCurrentProxy(oldProxy);
                }
            }
        }
        //省略...
    }
 
 
    /**
     * Implementation of AOP Alliance MethodInvocation used by this AOP proxy.
     */
    private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
 
        private final MethodProxy methodProxy;
 
        private final boolean publicMethod;
 
        public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments,
                Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
 
            super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
            this.methodProxy = methodProxy;
            this.publicMethod = Modifier.isPublic(method.getModifiers());
        }
 
        /**
         * Gives a marginal performance improvement versus using reflection to
         * invoke the target when invoking public methods.
         */
        @Override
        protected Object invokeJoinpoint() throws Throwable {
            if (this.publicMethod) {
                return this.methodProxy.invoke(this.target, this.arguments);
            }
            else {
                return super.invokeJoinpoint();
            }
        }
    }
 
}

8、各種Advice是的執(zhí)行順序是如何和方法調(diào)用進行結(jié)合的?

JdkDynamicAopProxy 和CglibAopProxy只是創(chuàng)建代理方式的兩種方式而已,實際上我們?yōu)榉椒ㄕ{(diào)用添加的各種Advice的執(zhí)行邏輯都是統(tǒng)一的。在Spring的底層,會把我們定義的各個Adivce分別 包裹成一個 MethodInterceptor,這些Advice按照加入Advised順序,構(gòu)成一個AdivseChain.

比如我們下面的代碼:

        //5. 添加不同的Advice
 
        proxyFactoryBean.addAdvice(afterReturningAdvice);
        proxyFactoryBean.addAdvice(aroundAdvice);
        proxyFactoryBean.addAdvice(throwsAdvice);
        proxyFactoryBean.addAdvice(beforeAdvice);
        proxyFactoryBean.setProxyTargetClass(false);
        //通過ProxyFactoryBean生成
        TicketService ticketService = (TicketService) proxyFactoryBean.getObject();
        ticketService.sellTicket();

當我們調(diào)用 ticketService.sellTicket()時,Spring會把這個方法調(diào)用轉(zhuǎn)換成一個MethodInvocation對象,然后結(jié)合上述的我們添加的各種Advice,組成一個ReflectiveMethodInvocation:

image.png

各種Advice本質(zhì)而言是一個方法調(diào)用攔截器,現(xiàn)在讓我們看看各個Advice攔截器都干了什么?

  • 攔截原理


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容