Spring AOP淺析(二) AOP實(shí)現(xiàn)分析

前文介紹了代理模式及實(shí)現(xiàn),但想要實(shí)現(xiàn)一個(gè)完整的AOP框架還遠(yuǎn)遠(yuǎn)不夠,接下來(lái)我們來(lái)分析一下Spring是如何實(shí)現(xiàn)AOP的棺弊。

1 AOP體系結(jié)構(gòu)

下圖AOP聯(lián)盟定義的AOP體系結(jié)構(gòu),大致分為從使用到實(shí)現(xiàn)的三個(gè)層次瞬女。整篇文章都將按照這三個(gè)層次進(jìn)行分析


1.1 層次3:語(yǔ)言和開發(fā)環(huán)境

  • 基礎(chǔ):可以視為待增強(qiáng)對(duì)象
  • 切面:通常包含對(duì)于基礎(chǔ)的增強(qiáng)應(yīng)用
  • 配置:指配置環(huán)境或編織配置,將基礎(chǔ)和切面結(jié)合起來(lái),從而實(shí)現(xiàn)對(duì)目標(biāo)對(duì)象的編織實(shí)現(xiàn)

Spring使用Java語(yǔ)言來(lái)實(shí)現(xiàn)增強(qiáng)對(duì)象和切面努潘,并為這兩者提供配置環(huán)境;對(duì)于編織配置诽偷,可以使用IoC容器來(lái)完成,而Ioc恰恰是Spring的強(qiáng)項(xiàng)疯坤。

1.2 層次2:面向方面系統(tǒng)

面向方面系統(tǒng)為上層的語(yǔ)言與開發(fā)環(huán)境提供支持报慕,將基礎(chǔ)、切面和配置封裝成面向方面中的邏輯模型压怠。

1.3 層次1:底層編織實(shí)現(xiàn)模塊

將編織邏輯進(jìn)行實(shí)現(xiàn)的技術(shù)眠冈。
前文所述的兩種動(dòng)態(tài)代理技術(shù)就是在這個(gè)層面進(jìn)行應(yīng)用。

2 Spring AOP實(shí)現(xiàn)

我們從上到下的看看Spring如何實(shí)現(xiàn)AOP的菌瘫。整個(gè)AOP框架邏輯流程很復(fù)雜蜗顽,這里就只對(duì)在目標(biāo)對(duì)象在單例模式下并使用JDK動(dòng)態(tài)代理的AOP進(jìn)行分析布卡。

2.1 層次3:語(yǔ)言和開發(fā)環(huán)境

2.1.1 基礎(chǔ)

在Spring中,基礎(chǔ)就是你配置的Bean對(duì)象雇盖,這個(gè)Bean對(duì)象可以配置在XML中忿等,也可以使用注解進(jìn)行配置,如<bean id="realSubject" class="com.magicalwolf.proxy.RealSubject" />

2.1.2 切面

在Spring中,切面由切點(diǎn)和通知組成崔挖,由使用者進(jìn)行定義.

PointCut切點(diǎn)

決定Advice通知應(yīng)該作用于哪個(gè)連接點(diǎn)贸街,也就是通過(guò)切點(diǎn)定義哪些方法需要增強(qiáng)。

PointCut接口是所有切點(diǎn)實(shí)現(xiàn)的基本接口狸相,其中定義了MethodMatcher方法薛匪,用來(lái)判斷當(dāng)前方法是否需要增強(qiáng)【砹ǎ可以通過(guò)不同的方式進(jìn)行判斷蛋辈,如JdkRegexpMethodPointcut類使用正則表達(dá)式進(jìn)行匹配属拾,還可以使用類限定名将谊,切點(diǎn)表達(dá)式等方式進(jìn)行匹配。

Advice通知

通知定義在連接點(diǎn)做什么渐白,為切面增強(qiáng)提供織入接口尊浓。Advice接口是AOP聯(lián)盟定義的統(tǒng)一接口,Spring對(duì)這個(gè)接口進(jìn)行了細(xì)化和擴(kuò)展纯衍,如BeforeAdvice,AfterAdvice,ThrowsAdvice

Advisor通知器

通知器將通知和切點(diǎn)結(jié)合起來(lái)栋齿,為Spring配置AOP容器提供便利。

2.1.3 配置

對(duì)基礎(chǔ)和切面進(jìn)行配置襟诸,使之對(duì)基礎(chǔ)進(jìn)行增強(qiáng).Spring實(shí)現(xiàn)多種方式的配置瓦堵,ProxyFactoryBean完成聲明式配置,ProxyFactory完成編程式配置歌亲。AspectJProxyFactory將Spring和Aspectj集成菇用。

2.1.4 使用ProxyFactoryBean的示例

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context" xmlns="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 目標(biāo)對(duì)象 -->
    <bean id="realSubject" class="com.magicalwolf.proxy.RealSubject" />
    <!-- 通知 -->
    <bean id="requestAdvice" class="com.magicalwolf.spring.aop.RequestBeforeAdvice" />
    <!-- 通知器 -->
    <bean id="requestAdvisor"
        class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
        <property name="advice">
            <ref bean="requestAdvice" />
        </property>

        <property name="mappedName">
            <value>request</value>
        </property>
    </bean>
    <!-- 代理工廠 -->
    <bean id="requestAOP" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces" value="com.magicalwolf.proxy.Subject" />
        <property name="target">
            <ref bean="realSubject" />
        </property>
        <property name="interceptorNames">
            <list>
                <value>requestAdvisor</value>
            </list>
        </property>
    </bean>
</beans>

RequestBeforeAdvice.java

public class RequestBeforeAdvice implements MethodBeforeAdvice{
    private void before(String param) throws Throwable{
        if(!param.equals("magicalwolf"))
            throw new IllegalArgumentException();
    }
    @Override
    public void before(Method method, Object[] args, Object target)
            throws Throwable {
        before((String)args[0]);
    }
}

Main.java

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Subject proxy= (Subject) context.getBean("requestAOP");
        proxy.request("magicalwolf");
        proxy.request("hello");
    }
}

層次3主要定義了開發(fā)人員如何使用AOP,Spring在背后將進(jìn)行邏輯模型的封裝工作

2.2 層次2:面向方面系統(tǒng)

我們從ProxyFactoryBean出發(fā)陷揪,看看面向方面系統(tǒng)是如何對(duì)target目標(biāo)起作用的惋鸥。

2.2.1 ProxyFactoryBean的繼承關(guān)系

  • ProxyFactoryBean類負(fù)責(zé)具體AOP代理對(duì)象的生成
  • ProxyCreateSupport類是創(chuàng)建AOP代理對(duì)象的一個(gè)輔助類
  • AdvisedSupport類封裝了對(duì)通知和通知器相關(guān)的操作
  • ProxyConfig類為子類提供配置屬性

2.2.2 生成代理對(duì)象跟蹤

從FactoryBean中獲取對(duì)象,是以getObject()方法為入口悍缠,在ProxyFactoryBean也是如此卦绣,getObject()方法對(duì)目標(biāo)對(duì)象進(jìn)行增強(qiáng)處理。

2.2.2.1 public Object getObject()

首先對(duì)通知器鏈進(jìn)行初始化飞蚓,生成代理對(duì)象時(shí)如果是單例模式調(diào)用getSingletonInstance(),此處只分析單例的情況

public Object getObject() throws BeansException {
    initializeAdvisorChain();//初始化通知器鏈(2.2.2.2)
    if (isSingleton()) {
        return getSingletonInstance();//生成Singleton的代理對(duì)象(2.2.2.3)
    }
    else {
        if (this.targetName == null) {
            logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
                    "Enable prototype proxies by setting the 'targetName' property.");
        }
        return newPrototypeInstance();
    }
}
2.2.2.2 private synchronized void initializeAdvisorChain()

初始化通知器鏈滤港,此方法是線程安全的

private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
    if (this.advisorChainInitialized) {
        return;
    }
    /檢查interceptorNames是否為空,interceptorNames是一個(gè)String[]
    if (!ObjectUtils.isEmpty(this.interceptorNames)) {
        //檢查beanFactory是否為null趴拧,此處的beanFactory是Spring的Bean工廠,直接從容器中獲得配置的通知器
        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");
        }

        // 通過(guò)Bean Name獲得通知器
        for (String name : this.interceptorNames) {
            if (logger.isTraceEnabled()) {
                logger.trace("Configuring advisor or advice '" + name + "'");
            }
            //GLOBAL_SUFFIX = "*"蜗搔,說(shuō)明這個(gè)通知器是全局通知器
            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 {
                // 添加一個(gè)命名的通知器劲藐,檢查是singleton還是prototype
                Object advice;
                if (this.singleton || this.beanFactory.isSingleton(name)) {
                    // 獲得一個(gè)Advice或Advisor
                    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);//添加通知器到通知器列表(2.2.6)
            }
        }
    }

    this.advisorChainInitialized = true;
}
2.2.2.3 private synchronized Object getSingletonInstance()
private synchronized Object getSingletonInstance() {
    //singletonInstance為緩存的單例對(duì)象,如果存在就直接返回
    if (this.singletonInstance == null) {
        this.targetSource = freshTargetSource();//targetSource在AdvisedSupport中定義樟凄,用來(lái)獲得目標(biāo)對(duì)象
        if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
            //依靠AOP框架告訴我們哪個(gè)接口被代理
            Class<?> targetClass = getTargetClass();
            if (targetClass == null) {
                throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
            }
            //設(shè)置代理接口聘芜,在AdvisedSupport中定義了interfaces列表
            setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
        }
        super.setFrozen(this.freezeProxy);
        //使用ProxyFactory生成需要的Proxy
        this.singletonInstance = getProxy(createAopProxy());
        //getProxy(2.2.2.4),createAopProxy(2.2.2.5)
    }
    return this.singletonInstance;
}
2.2.2.4 protected Object getProxy(AopProxy aopProxy)

AopProxy是一個(gè)接口缝龄,有兩個(gè)子類實(shí)現(xiàn)汰现,一個(gè)是ObjenesisCglibAopProxy,一個(gè)是JdkDynamicProxy.分別通過(guò)CGLIB和JDK來(lái)生成需要的Proxy代理對(duì)象

protected Object getProxy(AopProxy aopProxy) {
    //通過(guò)AopProxy得到代理對(duì)象
    return aopProxy.getProxy(this.proxyClassLoader);
}
2.2.2.5 protected final synchronized AopProxy createAopProxy()

此方法在ProxyCreatorSupport中定義,具體是通過(guò)AopProxyFactory來(lái)獲得AopProxy叔壤,AopProxyFactory默認(rèn)的工廠實(shí)現(xiàn)是DefaultAopProxyFactory瞎饲,生成哪一種AopProxy就在此類中定義

protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
        activate();
    }
    return getAopProxyFactory().createAopProxy(this);
}

DefaultAopProxyFactory中的createAopProxy方法

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        Class<?> targetClass = config.getTargetClass();
        //檢查目標(biāo)對(duì)象是否存在
        if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: " +
                    "Either an interface or a target is required for proxy creation.");
        }
        //如果是接口類使用JDK生成Proxy
        if (targetClass.isInterface()) {
            return new JdkDynamicAopProxy(config);
        }
        //否則用cglib
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        return new JdkDynamicAopProxy(config);
    }
}

JdkDynamicAopProxy中的getObject方法,這里我們可以看到熟悉的Proxy.newProxyInstance()方法

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);
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
2.2.2.6 private void addAdvisorOnChainCreation(Object next, String name)

namedBeanToAdvisor方法會(huì)將next對(duì)象包裝為Advisor對(duì)象炼绘,并添加到Advisor集合中

private void addAdvisorOnChainCreation(Object next, String name) {
    Advisor advisor = namedBeanToAdvisor(next);
    if (logger.isTraceEnabled()) {
        logger.trace("Adding advisor with name '" + name + "'");
    }
    addAdvisor(advisor);
}

namedBeanToAdvisor方法中嗅战,會(huì)使用DefaultAdvisorAdapterRegistry的warp方法對(duì)next對(duì)象進(jìn)行包裝.通知器是由切點(diǎn)和通知組成,如果只配置了通知俺亮,則切點(diǎn)為默認(rèn)的TruePointcut,它對(duì)任何方法的匹配都將返回true

public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
    //如果對(duì)象已經(jīng)是Advisor直接返回
    if (adviceObject instanceof Advisor) {
        return (Advisor) adviceObject;
    }
    //檢查類型
    if (!(adviceObject instanceof Advice)) {
        throw new UnknownAdviceTypeException(adviceObject);
    }
    Advice advice = (Advice) adviceObject;
    if (advice instanceof MethodInterceptor) {
        // 包裝為默認(rèn)切點(diǎn)通知器
        return new DefaultPointcutAdvisor(advice);
    }
    for (AdvisorAdapter adapter : this.adapters) {
        // 檢查是否匹配
        if (adapter.supportsAdvice(advice)) {
            return new DefaultPointcutAdvisor(advice);
        }
    }
    throw new UnknownAdviceTypeException(advice);
}

通過(guò)以上的分析驮捍,我們已經(jīng)得到了代理對(duì)象,至此層次2的工作已經(jīng)完成了脚曾,層次3獲得的配置模型东且,在配置邏輯的應(yīng)用下向AOP模型轉(zhuǎn)換,接下來(lái)該層次1的實(shí)現(xiàn)了

2.2 層次1:底層編織實(shí)現(xiàn)模塊

在生成代理對(duì)象的時(shí)候本讥,相關(guān)的攔截器已經(jīng)配置完成珊泳,攔截器起作用是通過(guò)對(duì)方法進(jìn)行回掉完成的。

2.2.1 使用JDK代理的實(shí)現(xiàn)

前文提到過(guò)拷沸,在JDK代理中方法回掉的入口是在invoke方法中色查。而JdkDynamicAopProxy實(shí)現(xiàn)了InvocationHandler接口,方法回掉邏輯也定義在其中.

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)) {
            // 目標(biāo)沒(méi)有實(shí)現(xiàn)自己的equals方法
            return equals(args[0]);
        }
        if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // 目標(biāo)沒(méi)有實(shí)現(xiàn)自己的hashCodes方法
            return hashCode();
        }
        if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                method.getDeclaringClass().isAssignableFrom(Advised.class)) {
            // 根據(jù)代理對(duì)象的配置調(diào)用服務(wù)撞芍,如果是Advised接口的實(shí)現(xiàn)類秧了,則直接調(diào)用
            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
        }

        Object retVal;

        if (this.advised.exposeProxy) {
            // Make invocation available if necessary.
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        // 有可能為null.盡可能減少擁有目標(biāo)對(duì)象的時(shí)間,在這種情況下對(duì)象來(lái)自于對(duì)象池
        target = targetSource.getTarget();
        if (target != null) {
            targetClass = target.getClass();
        }

        // 獲得這個(gè)方法的連接器鏈
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);//2.2.2
        //如果沒(méi)有攔截器鏈勤庐,則直接調(diào)用目標(biāo)對(duì)象
        if (chain.isEmpty()) {
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
        }
        else {
            // 構(gòu)造一個(gè)方法調(diào)用
            invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // 調(diào)用連接點(diǎn)的攔截器鏈(2.2.3)
            retVal = invocation.proceed();
        }

        Class<?> returnType = method.getReturnType();
        if (retVal != null && retVal == target && 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);
        }
        return retVal;
    }
    finally {
        if (target != null && !targetSource.isStatic()) {
            // 必須來(lái)自TargetSource.
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            // 重新保存舊的代理
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}

invoke方法獲取目標(biāo)對(duì)象和攔截器鏈示惊,并生成ReflectiveMethodInvocation對(duì)象,通過(guò)這個(gè)對(duì)象完成對(duì)AOP功能的封裝愉镰。

2.2.2 獲得方法的攔截器鏈

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    List<Object> cached = this.methodCache.get(cacheKey);//
    if (cached == null) {
        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                this, method, targetClass);
        this.methodCache.put(cacheKey, cached);
    }
    return cached;
}

methodCache是一個(gè)集合Map<MethodCacheKey, List<Object>>,對(duì)方法的攔截器鏈進(jìn)行緩存米罚,如果不在緩存中,則生成并添加丈探。這里使用DefaultAdvisorChainFactory來(lái)生成攔截器鏈

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

    //通過(guò)config獲得配置好的advisor鏈录择,AdvisedSupport實(shí)現(xiàn)了Advised
    List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
    //實(shí)際對(duì)象
    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) {
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            //判斷通知器是否匹配實(shí)際對(duì)象
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                MethodInterceptor[] interceptors = registry.getInterceptors(advisor);//將通知器適配成方法攔截
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
                    if (mm.isRuntime()) {
                        for (MethodInterceptor interceptor : interceptors) {
                            //封裝成動(dòng)態(tài)方法匹配
                            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;
}

此方法有一個(gè)適配和注冊(cè)的過(guò)程,它將Advice通知適配成Spring預(yù)先設(shè)計(jì)好的攔截器。適配和注冊(cè)的工作是在GlobalAdvisorAdapterRegistry的getInterceptors()中完成的

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
    List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
    Advice advice = advisor.getAdvice();//獲得通知
    if (advice instanceof MethodInterceptor) {//如果是MethodInterceptor則直接添加
        interceptors.add((MethodInterceptor) advice);
    }
    for (AdvisorAdapter adapter : this.adapters) {//遍歷注冊(cè)的適配器隘竭,檢查是否匹配
        if (adapter.supportsAdvice(advice)) {
            interceptors.add(adapter.getInterceptor(advisor));
        }
    }
    if (interceptors.isEmpty()) {
        throw new UnknownAdviceTypeException(advisor.getAdvice());
    }
    return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
}

GlobalAdvisorAdapterRegistry的構(gòu)造函數(shù)中注冊(cè)了三種適配器塘秦,注冊(cè)過(guò)程就是將這三種適配器加入List集合

public DefaultAdvisorAdapterRegistry() {
    registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
    registerAdvisorAdapter(new AfterReturningAdviceAdapter());
    registerAdvisorAdapter(new ThrowsAdviceAdapter());
}

來(lái)看一下MethodBeforeAdviceAdapter

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
    @Override
    public boolean supportsAdvice(Advice advice) {//是否支持
        return (advice instanceof MethodBeforeAdvice);
    }
    @Override
    public MethodInterceptor getInterceptor(Advisor advisor) {//將Advice適配成Interceptor
        MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
        return new MethodBeforeAdviceInterceptor(advice);
    }
}

將Advice封裝成了MethodBeforeAdviceInterceptor,此類中有invoke方法,會(huì)先調(diào)用advice的before方法

public Object invoke(MethodInvocation mi) throws Throwable {
    this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
    return mi.proceed();
}

至此动看,Spring AOP實(shí)現(xiàn)了對(duì)advice的織入尊剔,可以看到它將xml中配置的通知器適配成了攔截器

2.2.3 方法調(diào)用

之前講到了攔截器的適配和注冊(cè),對(duì)呀?jīng)]有攔截器的方法直接調(diào)用菱皆,有攔截器的方法會(huì)構(gòu)造ReflectiveMethodInvocation须误,并沿著攔截器鏈進(jìn)行調(diào)用。整個(gè)調(diào)用鏈的入口在proceed方法中

public Object proceed() throws Throwable {
    //從索引為-1的攔截器開始仇轻,并遞增
    //如果攔截器迭代調(diào)用完成京痢,則調(diào)用目標(biāo)方法
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();//使用invokeJoinpointUsingReflection調(diào)用目標(biāo)對(duì)象
    }
    //沿著攔截器鏈執(zhí)行
    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        //對(duì)方法進(jìn)行動(dòng)態(tài)匹配,切點(diǎn)的匹配就在這里進(jìn)行
        InterceptorAndDynamicMethodMatcher dm =
                (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
            return dm.interceptor.invoke(this);
        }
        else {
            // 動(dòng)態(tài)匹配失敗
            // 跳過(guò)這個(gè)攔截器調(diào)用下一個(gè)
            return proceed();
        }
    }
    else {
        // 這是一個(gè)攔截器篷店,直接調(diào)用它
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

至此祭椰,完成對(duì)攔截器鏈及目標(biāo)方法的調(diào)用

3 總結(jié)

3.1 層次3:語(yǔ)言與開發(fā)環(huán)境

Spring AOP使用Java語(yǔ)言,可以通過(guò)多種方式進(jìn)行AOP配置疲陕,基礎(chǔ)就是Bean對(duì)象方淤,切面可以通過(guò)xml或注解進(jìn)行聲明.配置是由IoC容器完成的

3.2 層次2:面向方面系統(tǒng)

本文分析使用ProxyFactoryBean的情況,ProxyFactoryBean處理配置邏輯,生成代理對(duì)象鸭轮。ProxyFactoryBean會(huì)先初始化通知器集合臣淤,再根據(jù)代理類型使用JdkDynamicProxyObjenesisCglibAopProxy生成代理對(duì)象

3.1 層次1:底層編織實(shí)現(xiàn)模塊

使用JDK代理中橄霉,方法的回掉入口在invoke方法中窃爷,在invoke方法中實(shí)現(xiàn)了Advice的織入,以及目標(biāo)方法的調(diào)用姓蜂。
對(duì)Advice的織入按厘,Spring預(yù)先設(shè)計(jì)好了攔截器,如MethodBeforeAdviceInterceptor,AfterReturningAdviceInterceptor,ThrowsAdviceInterceptor,將Advice適配成對(duì)應(yīng)的攔截器钱慢,并將攔截器鏈緩存,此時(shí)完成了對(duì)Advice的織入
對(duì)目標(biāo)方法的調(diào)用逮京,如果在目標(biāo)方法未配置攔截器,則直接調(diào)用目標(biāo)方法束莫,如果得到了攔截器鏈懒棉,則沿著攔截器鏈執(zhí)行。在執(zhí)行過(guò)程中如果是動(dòng)態(tài)匹配的攔截器览绿,則需要再次進(jìn)行匹配策严,否則直接調(diào)用攔截器。

以上分析了Spring AOP的部分實(shí)現(xiàn)饿敲,不過(guò)整個(gè)AOP基本流程已經(jīng)分析完成妻导。有了基礎(chǔ)再去看AOP的高級(jí)部分會(huì)更加容易

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子倔韭,更是在濱河造成了極大的恐慌术浪,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寿酌,死亡現(xiàn)場(chǎng)離奇詭異胰苏,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)醇疼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門碟联,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人僵腺,你說(shuō)我怎么就攤上這事鲤孵。” “怎么了辰如?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵普监,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我琉兜,道長(zhǎng)凯正,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任豌蟋,我火速辦了婚禮廊散,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘梧疲。我一直安慰自己允睹,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布幌氮。 她就那樣靜靜地躺著缭受,像睡著了一般。 火紅的嫁衣襯著肌膚如雪该互。 梳的紋絲不亂的頭發(fā)上米者,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音宇智,去河邊找鬼蔓搞。 笑死,一個(gè)胖子當(dāng)著我的面吹牛随橘,可吹牛的內(nèi)容都是我干的喂分。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼太防,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼妻顶!你這毒婦竟也來(lái)了酸员?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤讳嘱,失蹤者是張志新(化名)和其女友劉穎幔嗦,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體沥潭,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡邀泉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了钝鸽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汇恤。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖拔恰,靈堂內(nèi)的尸體忽然破棺而出因谎,到底是詐尸還是另有隱情,我是刑警寧澤颜懊,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布财岔,位于F島的核電站,受9級(jí)特大地震影響河爹,放射性物質(zhì)發(fā)生泄漏匠璧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一咸这、第九天 我趴在偏房一處隱蔽的房頂上張望夷恍。 院中可真熱鬧,春花似錦媳维、人聲如沸酿雪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)执虹。三九已至拓挥,卻和暖如春唠梨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背侥啤。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工当叭, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人盖灸。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓蚁鳖,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親赁炎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子醉箕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理钾腺,服務(wù)發(fā)現(xiàn),斷路器讥裤,智...
    卡卡羅2017閱讀 134,599評(píng)論 18 139
  • 本博中關(guān)于spring的文章:Spring IOC和AOP原理放棒,Spring事務(wù)原理探究,Spring配置文件屬性...
    Maggie編程去閱讀 4,096評(píng)論 0 34
  • 什么是Spring Spring是一個(gè)開源的Java EE開發(fā)框架己英。Spring框架的核心功能可以應(yīng)用在任何Jav...
    jemmm閱讀 16,441評(píng)論 1 133
  • title: Spring_AOP源碼分析date: 2016-11-03 01:15:11categories:...
    raincoffee閱讀 1,731評(píng)論 2 36
  • 前陣子回了趟老家损肛,與多年未見的高中同學(xué)進(jìn)行聚會(huì)厢破。十多年未見,真是彈指一揮間治拿,大家除了感嘆時(shí)光的無(wú)情之外摩泪,更多則是驚...
    伊伊8899閱讀 660評(píng)論 7 12