spring aop學(xué)習(xí)總結(jié)

AOP概述

  1. AOP定義概念


    這里寫圖片描述

    這里我們只要關(guān)注三個(gè)重點(diǎn)的概念:
    1)基礎(chǔ)(base):目標(biāo)對象
    2)切面(aspect):通知、增強(qiáng)目標(biāo)對象的應(yīng)用
    3)配置(configuration):編織(將目標(biāo)對象和切面結(jié)合起來)

  2. Pointcut切點(diǎn)

我們來看一下對于MethodMatcher對象和matches方法的API說明
MethodMatcher:Checks whether the target method is eligible for advice.A MethodMatcher may be evaluated statically or at runtime (dynamically).Static matching involves method and (possibly) method attributes. Dynamic matching also makes arguments for a particular call available, and any effects of running
previous advice applying to the joinpoint.
檢查目標(biāo)方法是否與切面匹配,動(dòng)態(tài)和靜態(tài)匹配都包含了方法和方法參數(shù)信息來與切面進(jìn)行匹配。
matches:Perform static checking whether the given method matches.
校驗(yàn)?zāi)繕?biāo)方法是否匹配的具體執(zhí)行方法,返回boolean值

  1. Advisor通知器
    用來將切面和目標(biāo)對象結(jié)合起來,完成這個(gè)作用的就是Advisor通知器。
public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable {

    private Pointcut pointcut = Pointcut.TRUE;

    public DefaultPointcutAdvisor() {
    }

    //匹配所有方法(任務(wù)方法都會(huì)被此通知的切面攔截)
    public DefaultPointcutAdvisor(Advice advice) {
        this(Pointcut.TRUE, advice);
    }

    public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {
        this.pointcut = pointcut;
        setAdvice(advice);
    }

    //設(shè)置目標(biāo)對象
    public void setPointcut(Pointcut pointcut) {
        this.pointcut = (pointcut != null ? pointcut : Pointcut.TRUE);
    }

    @Override
    public Pointcut getPointcut() {
        return this.pointcut;
    }

    @Override
    public String toString() {
        return getClass().getName() + ": pointcut [" + getPointcut() + "]; advice [" + getAdvice() + "]";
    }

}

DefaultPointcutAdvisor是通知接口Advisor接口的一個(gè)實(shí)現(xiàn),有兩個(gè)屬性,分別是advice和pointcut,用來分配配置Advice和Pointcut。

AopProxy代理對象

  1. 設(shè)計(jì)原理
    AOP是通過配置和調(diào)用spring的ProxyFactoryBean來完成。ProxyFactoryBean封裝了代理對象的生成過程。

大致類圖:


  1. ProxyFactoryBean配置
<bean id="testAdvisor" class="com.TestAdvisor"/>
<bean id="testAop" class="org.springframework.aop.framework.ProxyFactoryBean"
        p:proxyInterfaces="targetInterfaces"
        p:interceptorNames="testAdvisor"
        p:target-ref="target"/>
  • target:代理的目標(biāo)對象

  • proxyInterfaces:代理所需要實(shí)現(xiàn)的接口,可以多個(gè)接口。該屬性還有一個(gè)別名是Interfaces

  • interceptorNames:需要植入目標(biāo)對象的bean列表。采用bean的名稱指定。這些bean必須實(shí)現(xiàn)類 org.aopalliance.intercept.MethodInterceptor 或 org.springframework.aop.Advisor的bean ,配置中的順序?qū)?yīng)調(diào)用的順序。

  • proxyTargetClass:是否對類進(jìn)行代理(而不是進(jìn)行對接口進(jìn)行代理),設(shè)置為true時(shí),使用CGLib代理,且proxyInterfaces屬性被ProxyFactoryBean忽略。

    1. ProxyFactoryBean生成AopProxy代理對象
      ProxyFactoryBean生成代理對象以getObject方法作為入口。


      這里寫圖片描述

我們來看下通知器配置鏈的初始化過程(ProxyFactoryBean.initializeAdvisorChain方法)

private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
        if (this.advisorChainInitialized) {
            return;
        }

        if (!ObjectUtils.isEmpty(this.interceptorNames)) {
            if (this.beanFactory == null) {
                throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
                        "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
            }

            // Globals can't be last unless we specified a targetSource using the property...
            if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
                    this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
                throw new AopConfigException("Target required after globals");
            }

            // Materialize interceptor chain from bean names.
            for (String name : this.interceptorNames) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Configuring advisor or advice '" + name + "'");
                }

                //若interceptorNames配置成aaa*,則獲取所有aaa開頭的advisor
                if (name.endsWith(GLOBAL_SUFFIX)) {
                    if (!(this.beanFactory instanceof ListableBeanFactory)) {
                        throw new AopConfigException(
                                "Can only use global advisors or interceptors with a ListableBeanFactory");
                    }
                    addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
                            name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
                }

                else {
                    // If we get here, we need to add a named interceptor.
                    // We must check if it's a singleton or prototype.
                    Object advice;
                    if (this.singleton || this.beanFactory.isSingleton(name)) {
                        // Add the real Advisor/Advice to the chain.
                        // 通過ioc容器或切面實(shí)例
                        advice = this.beanFactory.getBean(name);
                    }
                    else {
                        // It's a prototype Advice or Advisor: replace with a prototype.
                        // Avoid unnecessary creation of prototype bean just for advisor chain initialization.
                        advice = new PrototypePlaceholderAdvisor(name);
                    }
                    addAdvisorOnChainCreation(advice, name);
                }
            }
        }

        this.advisorChainInitialized = true;
    }

最終所有配置的切面對象實(shí)例都會(huì)被放置到AdvisedSupport輔助類的List容器中


??addAdvisorOnChainCreation方法會(huì)調(diào)用DefaultAdvisorAdapterRegistry的wrap

    @Override
    public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
        if (adviceObject instanceof Advisor) {
            return (Advisor) adviceObject;
        }
        //若配置的既不是通知器,也不是advice接口的實(shí)現(xiàn)類,拋出異常
        if (!(adviceObject instanceof Advice)) {
            throw new UnknownAdviceTypeException(adviceObject);
        }
        Advice advice = (Advice) adviceObject;
        //將自定義的advice切面封裝成通知器
        if (advice instanceof MethodInterceptor) {
            // So well-known it doesn't even need an adapter.
            return new DefaultPointcutAdvisor(advice);
        }
        for (AdvisorAdapter adapter : this.adapters) {
            // Check that it is supported.
            if (adapter.supportsAdvice(advice)) {
                return new DefaultPointcutAdvisor(advice);
            }
        }
        throw new UnknownAdviceTypeException(advice);
    }

生成singleton代理對象在getSingletonInstance()方法中完成,這個(gè)方法是生成AopProxy代理對象的入口。
最終通過DefaultAopProxyFactory獲取AopProxy
代碼如下

    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: " +
                        "Either an interface or a target is required for proxy creation.");
            }
            //目標(biāo)類是否是接口類
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                //生成jdk代理對象
                return new JdkDynamicAopProxy(config);
            }
            //生成cglib代理對象
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }

具體的代理對象則有AopProxy(JdkDynamicAopProxy、ObjenesisCglibAopProxy extend CglibAopProxy)類中的getProxy方法來完成。
我們通過JdkDynamicAopProxy來研究下Proxy的切面攔截策略

/**
     * 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 {
            //如果沒有實(shí)現(xiàn)object的基本方法,代理對象會(huì)代理生成一個(gè)
            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;
            }

            // 獲取目標(biāo)對象
            target = targetSource.getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }

            // 獲取此方法定義好的切面攔截器
            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)用目標(biāo)方法
            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...
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // Proceed to the joinpoint through the interceptor chain.
                // 通過攔截器調(diào)用目標(biāo)方法
                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);
            }
        }
    }

下面我們看看代理對象是如何通過List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);獲取目標(biāo)對象的攔截器集合的。
interceptor鏈的獲取是在DefaultAdvisorChainFactory中實(shí)現(xiàn)的

@Override
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
            Advised config, Method method, Class<?> targetClass) {

        List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
        Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
        boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

        for (Advisor advisor : config.getAdvisors()) {
            if (advisor instanceof PointcutAdvisor) {
                //獲取切點(diǎn)信息
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                    //切點(diǎn)是否符合切面的配置信息
                    if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
                        if (mm.isRuntime()) {
                            // Creating a new object instance in the getInterceptors() method
                            // isn't a problem as we normally cache created chains.
                            for (MethodInterceptor interceptor : interceptors) {
                                interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                            }
                        }
                        else {
                            interceptorList.addAll(Arrays.asList(interceptors));
                        }
                    }
                }
            }
            else if (advisor instanceof IntroductionAdvisor) {
                IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
                if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                    Interceptor[] interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            }
            else {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }

        return interceptorList;
    }

返回的interceptorList集合包含了符合此切點(diǎn)的所有切面對象。
至此,我們已經(jīng)有了目標(biāo)對象和所有的切面對象。
接下來便是依次執(zhí)行攔截器并執(zhí)行調(diào)用方法
retVal = invocation.proceed();
我們跟到ReflectiveMethodInvocation的proceed方法

@Override
    public Object proceed() throws Throwable {
        //  We start with an index of -1 and increment early.
        //攔截器全部被遞歸調(diào)用過后,執(zhí)行目標(biāo)方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }

        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            // Evaluate dynamic method matcher here: static part will already have
            // been evaluated and found to match.
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                //若目標(biāo)方法需要被此攔截器攔截,遞歸調(diào)用攔截器,攔截器的invoke方法中會(huì)再次回掉this.proceed方法
                return dm.interceptor.invoke(this);
            }
            else {
                // Dynamic matching failed.
                // Skip this interceptor and invoke the next in the chain.
                //不需要被此攔截器攔截,直接遞歸調(diào)用this.proceed方法
                return proceed();
            }
        }
        else {
            // It's an interceptor, so we just invoke it: The pointcut will have
            // been evaluated statically before this object was constructed.
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }
  1. AOP通知實(shí)現(xiàn)
    下面有個(gè)問題,攔截器有一共有三種,前置,后期,異常,那么interceptorList中的攔截器是如何被區(qū)分開的呢?
    下面我們來分析一下,首先我們要從上段代碼中關(guān)注兩行代碼
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
    這里的registry是AdvisorAdapterRegistry的一個(gè)實(shí)現(xiàn)類DefaultAdvisorAdapterRegistry
    我們來具體看看DefaultAdvisorAdapterRegistry的實(shí)現(xiàn)
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
    //集合中存放了spring aop的3種攔截類型的對象
    private final List<AdvisorAdapter> adapters = new ArrayList<AdvisorAdapter>(3);

    /**
     * Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.
     */
    public DefaultAdvisorAdapterRegistry() {
        //將前置、后置、異常攔截器對象注冊到adapters集合中
        registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
        registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        registerAdvisorAdapter(new ThrowsAdviceAdapter());
    }

    @Override
    public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
        if (adviceObject instanceof Advisor) {
            return (Advisor) adviceObject;
        }
        if (!(adviceObject instanceof Advice)) {
            throw new UnknownAdviceTypeException(adviceObject);
        }
        Advice advice = (Advice) adviceObject;
        if (advice instanceof MethodInterceptor) {
            // So well-known it doesn't even need an adapter.
            return new DefaultPointcutAdvisor(advice);
        }
        for (AdvisorAdapter adapter : this.adapters) {
            // Check that it is supported.
            if (adapter.supportsAdvice(advice)) {
                return new DefaultPointcutAdvisor(advice);
            }
        }
        throw new UnknownAdviceTypeException(advice);
    }

    @Override
    public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
        List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
        //獲取此通知的切面
        Advice advice = advisor.getAdvice();
        if (advice instanceof MethodInterceptor) {
            interceptors.add((MethodInterceptor) advice);
        }
        //對此切面進(jìn)行適配,將其封裝為已經(jīng)配置好的AfterReturningAdviceInterceptor,MethodBeforeAdviceInterceptor,ThrowsAdviceInterceptor對象
        for (AdvisorAdapter adapter : this.adapters) {
            if (adapter.supportsAdvice(advice)) {
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }
        if (interceptors.isEmpty()) {
            throw new UnknownAdviceTypeException(advisor.getAdvice());
        }
        return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
    }

    @Override
    public void registerAdvisorAdapter(AdvisorAdapter adapter) {
        this.adapters.add(adapter);
    }

}

封裝過程以MethodBeforeAdviceAdapter為例

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {

    @Override
    public boolean supportsAdvice(Advice advice) {
        return (advice instanceof MethodBeforeAdvice);
    }

    @Override
    public MethodInterceptor getInterceptor(Advisor advisor) {
        MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
        return new MethodBeforeAdviceInterceptor(advice);
    }

}

最后代理對象就通過調(diào)用MethodBeforeAdviceInterceptor中的invoke方法

這里寫圖片描述
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {

    private MethodBeforeAdvice advice;

    /**
     * Create a new MethodBeforeAdviceInterceptor for the given advice.
     * @param advice the MethodBeforeAdvice to wrap
     */
    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
        Assert.notNull(advice, "Advice must not be null");
        this.advice = advice;
    }

    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        //調(diào)用前置攔截器、
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
        //遞歸調(diào)用ReflectiveMethodInvocation的proceed方法執(zhí)行攔截器方法
        return mi.proceed();
    }

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

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

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