深入理解Spring 之 源碼剖析AOP(XML配置方式)

Spring 的兩大核心,一是IOC,我們之前已經(jīng)學(xué)習(xí)過,并且已經(jīng)自己動(dòng)手實(shí)現(xiàn)了一個(gè),而令一個(gè)則是大名鼎鼎的 AOP,AOP的具體概念我就不介紹了,我們今天重點(diǎn)是要從源碼層面去看看 spring 的 AOP 是如何實(shí)現(xiàn)的。注意,今天樓主給大家分享的是 XML 配置AOP的方式,不是我們經(jīng)常使用的注解方式,為什么呢?

有幾個(gè)原因:

  1. Spring AOP 在 2.0 版本之前都是使用的 XML 配置方式,封裝的層次相比注解要少,對(duì)于我們學(xué)習(xí)AOP是個(gè)很好的例子。
  2. 雖然現(xiàn)在是2017年,現(xiàn)在使用SpringBoot 都是使用注解了, 但是底層原理都是一樣的,只不過多了幾層封裝。當(dāng)然,我們也是要去扒開它的源碼的。但不是今天。
  3. 樓主也還沒有分析注解方式的AOP。-_-|||

我們主要分為幾個(gè)步驟去理解:

  1. 查看源碼了解 spring AOP 的接口設(shè)計(jì)。Advice,PointCut,Advisor。
  2. 用一個(gè)最簡單的代碼例子 debug 追蹤源碼。

那么我們現(xiàn)看第一步:

1. Spring AOP 接口設(shè)計(jì)

1.1 PointCut (連接點(diǎn),定義匹配哪些方法)

我們打開 Spring 的源碼,查看 PointCut 接口設(shè)計(jì):

public interface Pointcut {
    ClassFilter getClassFilter();
    MethodMatcher getMethodMatcher();
    Pointcut TRUE = TruePointcut.INSTANCE;
}

該接口定義了2 個(gè)方法,一個(gè)成員變量。我們先看第一個(gè)方法, ClassFilter getClassFilter() ,該方法返回一個(gè)類過濾器,由于一個(gè)類可能會(huì)被多個(gè)代理類代理,于是Spring引入了責(zé)任鏈模式,另一個(gè)方法則是 MethodMatcher getMethodMatcher() ,表示返回一個(gè)方法匹配器,我們知道,AOP 的作用是代理方法,那么,Spirng 怎么知道代理哪些方法呢?必須通過某種方式來匹配方法的名稱來決定是否對(duì)該方法進(jìn)行增強(qiáng),這就是 MethodMatcher 的作用。還有要給默認(rèn)的 Pointcut 實(shí)例,該實(shí)例對(duì)于任何方法的匹配結(jié)果都是返回 true。

我們關(guān)注一下 MethodMatcher 接口:

public interface MethodMatcher {
    boolean matches(Method method, @Nullable Class<?> targetClass);
    boolean isRuntime();
    boolean matches(Method method, @Nullable Class<?> targetClass, Object... args);
    MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}

該接口定義了靜態(tài)方法匹配器和動(dòng)態(tài)方法匹配器。所謂靜態(tài)方法匹配器,它僅對(duì)方法名簽名(包括方法名和入?yún)㈩愋图绊樞颍┻M(jìn)行匹配;而動(dòng)態(tài)方法匹配器,會(huì)在運(yùn)行期檢查方法入?yún)⒌闹怠lo態(tài)匹配僅會(huì)判別一次,而動(dòng)態(tài)匹配因?yàn)槊看握{(diào)用方法的入?yún)⒍伎赡懿灰粯樱悦看味急仨毰袛唷R话闱闆r下,動(dòng)態(tài)匹配不常用。方法匹配器的類型由isRuntime()返回值決定,返回false表示是靜態(tài)方法匹配器,返回true表示是動(dòng)態(tài)方法匹配器。

總的來說, PointCut 和 MethodMatcher 是依賴關(guān)系,定義了AOP應(yīng)該匹配什么方法以及如何匹配。

1.2 Advice (通知,定義在鏈接點(diǎn)做什么)

注意,Advice 接口只是一個(gè)標(biāo)識(shí),什么也沒有定義,但是我們常用的幾個(gè)接口,比如 BeforeAdvice,AfterAdvice,都是繼承自它。我們關(guān)注一下 AfterAdvice 的子接口 AfterReturningAdvice :

public interface AfterReturningAdvice extends AfterAdvice {
    void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;
}

該接口定義了一個(gè)方法,afterReturning,參數(shù)分別是返回值,目標(biāo)方法,參數(shù),目標(biāo)方法類,在目標(biāo)方法執(zhí)行之后會(huì)回調(diào)該方法。那么我們就可以在該方法中執(zhí)行我們的切面邏輯,BeforeAdvice 也是一樣的道理。

1.3 Advisor (通知器,將 Advice 和 PointCut 結(jié)合起來)

有了對(duì)目標(biāo)方法的增強(qiáng)接口 Advice 和 如何匹配目標(biāo)方法接口 PointCut 接口后,那么我們就需要用一個(gè)對(duì)象將他們結(jié)合起來,發(fā)揮AOP 的作用,所以Spring 設(shè)計(jì)了 Advisor(通知器),經(jīng)過我們剛剛的描述,我們應(yīng)該知道了,這個(gè) Advisor 肯定依賴了 Advice 和 PointCut,我們看看接口設(shè)計(jì):

public interface Advisor {

    Advice EMPTY_ADVICE = new Advice() {};

    Advice getAdvice();

    boolean isPerInstance();

}

還有他的子接口:

public interface PointcutAdvisor extends Advisor {

    Pointcut getPointcut();
}

最重要的兩個(gè)方法,getAdvice,getPointcut。和我們預(yù)想的基本一致。

接下來,我們可以停下來思考一下,現(xiàn)在有了這個(gè)東西,我們怎么實(shí)現(xiàn)面向切面編程;

  1. 首先我們需要告訴AOP在哪里進(jìn)行切面。比如在某個(gè)類的方法前后進(jìn)行切面。
  2. 告訴AOP 切面之后做什么,也就是說,我們知道了在哪里進(jìn)行切面,那么我們也該讓spring知道在切點(diǎn)處做什么。
  3. 我們知道,Spring AOP 的底層實(shí)現(xiàn)是動(dòng)態(tài)代理(不管是JDK還是Cglib),那么就需要一個(gè)代理對(duì)象,那么如何生成呢?

接下來,我們將通過代碼的方式,解答這三個(gè)疑惑。

2. 從一個(gè)簡單的AOP例子

首先,我們需要實(shí)現(xiàn)剛剛我們說的3個(gè)接口,還有一個(gè)目標(biāo)類,還要一個(gè)配置文件。一個(gè)一個(gè)來。

2.1. Pointcut 接口實(shí)現(xiàn)

package test;

import java.lang.reflect.Method;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;

public class TestPointcut implements Pointcut {

    @Override
    public ClassFilter getClassFilter() {
        return ClassFilter.TRUE;
    }

    @Override
    public MethodMatcher getMethodMatcher() {
        return new MethodMatcher() {

            public boolean matches(Method method, Class<?> targetClass, Object[] args) {
                if (method.getName().equals("test")) {
                    return true;
                }
                return false;
            }

            public boolean matches(Method method, Class<?> targetClass) {
                if (method.getName().equals("test")) {
                    return true;
                }
                return false;
            }

            public boolean isRuntime() {
                return true;
            }
        };
    }

}

我們?nèi)绾味x匹配?只要方法名稱是test則對(duì)該方法進(jìn)行增強(qiáng)或者說攔截。

2.2 AfterAdvice 實(shí)現(xiàn)

package test;

import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;

public class TestAfterAdvice implements AfterReturningAdvice {

    @Override
    public void afterReturning(Object returnValue, Method method,
            Object[] args, Object target) throws Throwable {
        System.out.println(
                "after " + target.getClass().getSimpleName() + "." + method.getName() + "()");
    }

}

我們在方法執(zhí)行完畢后打印該方法的名稱和該目標(biāo)類的名稱。這就是我們做的簡單增強(qiáng)。

2.3 Advisor 通知器的實(shí)現(xiàn)

package test;

import org.aopalliance.aop.Advice;
import org.springframework.aop.Pointcut;
import org.springframework.aop.PointcutAdvisor;

/**
 * 通知器
 */
public class TestAdvisor implements PointcutAdvisor {

    /**
     * 獲取通知處理邏輯
     */
    @Override
    public Advice getAdvice() {
        return new TestAfterAdvice();
    }

    @Override
    public boolean isPerInstance() {
        return false;
    }

    /**
     * 獲取切入點(diǎn)
     */
    @Override
    public Pointcut getPointcut() {
        return new TestPointcut();
    }

}

我們實(shí)現(xiàn)了 PointcutAdvisor 接口,返回我們剛才定義的兩個(gè)類。完成了他們的組合。

2.4 定義目標(biāo)類 Targe

package test;

public class TestTarget {

    public void test() {
        System.out.println("target.test()");
    }

    public void test2() {
        System.out.println("target.test2()");
    }
}

該目標(biāo)的實(shí)現(xiàn)和簡單,就是2個(gè)方法,分別打印自己的名字。

2.5 定義XML 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="testAdvisor" class="test.TestAdvisor"></bean>
    <bean id="testTarget" class="test.TestTarget"></bean>
    <bean id="testAOP" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="targetName">
            <value>testTarget</value>
        </property>
        <property name="interceptorNames">
            <list>
                <value>testAdvisor</value>
            </list>
        </property>
    </bean>

</beans>


可以看到,我們定義了3個(gè)bean,上面兩個(gè)是我們剛剛定義的,下面一個(gè)我們要好好說說,ProxyFactoryBean 是一個(gè)什么東西呢?首先他是一個(gè) FactoryBean,我們在學(xué)習(xí) IOC 的時(shí)候知道, FactoryBean 是Spring 留給我們擴(kuò)展用的,實(shí)現(xiàn)該接口的類可以自定類的各種功能。ProxyFactoryBean 當(dāng)然也實(shí)現(xiàn)了自己的很多自定義功能。ProxyFactoryBean 也是Spring IOC 環(huán)境中創(chuàng)建AOP 應(yīng)用的底層方法,Spring 正式通過它來實(shí)現(xiàn)對(duì)AOP的封裝。這樣我們更加接近Spring的底層設(shè)計(jì)。而該類需要注入兩個(gè)屬性一個(gè)目標(biāo)類,一個(gè)攔截類,ProxyFactoryBean 會(huì)生成一個(gè)動(dòng)態(tài)代理類來完成對(duì)目標(biāo)方法的攔截。

2.6 測試類

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class TestAOP {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new FileSystemXmlApplicationContext(
                "spring-context/src/test/java/test/beans.xml");
        TestTarget target = (TestTarget) applicationContext.getBean("testAOP");
        target.test();
        System.out.println("----------------");
        target.test2();
    }

}

我們看看運(yùn)行結(jié)果:

可以看到結(jié)果符合我們的預(yù)期,因?yàn)槲覀冎慌渲昧嗽趖est名稱的方法之后打印該方法的名稱和該目標(biāo)類的名稱,而test2 則沒有配置,因此也就沒有打印。

那么是怎么實(shí)現(xiàn)的呢? 讓我們進(jìn)入源碼看個(gè)究竟。

3. 深入 AOP 源碼實(shí)現(xiàn)

首先我們看看我們的測試代碼,我們第一句代碼是IOC 初始化,這個(gè)我們就不講了,我們在之前的文章已經(jīng)分析過,我們重點(diǎn)看第二行代碼,我們debug 到第三行,看看第二行返回的對(duì)象是什么?

我們看到,第二行從IOC容器中取出的是一個(gè)Cglib 生成的代理對(duì)象,也既是繼承了我們TestTarge 類的實(shí)例,而不是我們在 XML 中定義的 ProxyFactoryBean 對(duì)象,也就是說, FactoryBean 確實(shí)能夠在IOC容器中做一些定制化。那么我們就很好奇,這個(gè)代理對(duì)象是怎么生成的。我們從第二行代碼開始進(jìn)入。

首先進(jìn)入抽象類 AbstractApplicationContext 的getBean 方法,從容器或獲取 Bean,再調(diào)用 doGetBean 方法,這個(gè)方法我們很熟悉,因?yàn)樵僦暗腎OC過程中,我們看了好多遍了,我們重點(diǎn)看看該方法實(shí)現(xiàn):

    @SuppressWarnings("unchecked")
    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

        final String beanName = transformedBeanName(name);
        Object bean;

        // Eagerly check singleton cache for manually registered singletons.
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            if (logger.isDebugEnabled()) {
                if (isSingletonCurrentlyInCreation(beanName)) {
                    logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                            "' that is not fully initialized yet - a consequence of a circular reference");
                }
                else {
                    logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
            // Fail if we're already creating this bean instance:
            // We're assumably within a circular reference.
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            // Check if bean definition exists in this factory.
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                // Not found -> check parent.
                String nameToLookup = originalBeanName(name);
                if (parentBeanFactory instanceof AbstractBeanFactory) {
                    return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                            nameToLookup, requiredType, args, typeCheckOnly);
                }
                else if (args != null) {
                    // Delegation to parent with explicit args.
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else {
                    // No args -> delegate to standard getBean method.
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }

            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }

            try {
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);

                // Guarantee initialization of beans that the current bean depends on.
                String[] dependsOn = mbd.getDependsOn();// 設(shè)置依賴關(guān)系
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        if (isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
                        registerDependentBean(dep, beanName);
                        getBean(dep);// 遞歸
                    }
                }

                // Create bean instance.
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, () -> {// 創(chuàng)建bean
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            // Explicitly remove instance from singleton cache: It might have been put there
                            // eagerly by the creation process, to allow for circular reference resolution.
                            // Also remove any beans that received a temporary reference to the bean.
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);// 獲取實(shí)例
                }

                else if (mbd.isPrototype()) {
                    // It's a prototype -> create a new instance.
                    Object prototypeInstance = null;
                    try {
                        beforePrototypeCreation(beanName);
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                        afterPrototypeCreation(beanName);
                    }
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }

                else {
                    String scopeName = mbd.getScope();
                    final Scope scope = this.scopes.get(scopeName);
                    if (scope == null) {
                        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                    }
                    try {
                        Object scopedInstance = scope.get(beanName, () -> {
                            beforePrototypeCreation(beanName);
                            try {
                                return createBean(beanName, mbd, args);
                            }
                            finally {
                                afterPrototypeCreation(beanName);
                            }
                        });
                        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    }
                    catch (IllegalStateException ex) {
                        throw new BeanCreationException(beanName,
                                "Scope '" + scopeName + "' is not active for the current thread; consider " +
                                "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                                ex);
                    }
                }
            }
            catch (BeansException ex) {
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
        }

        // Check if required type matches the type of the actual bean instance.
        if (requiredType != null && !requiredType.isInstance(bean)) {
            try {
                T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
                if (convertedBean == null) {
                    throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
                }
                return convertedBean;
            }
            catch (TypeMismatchException ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Failed to convert bean '" + name + "' to required type '" +
                            ClassUtils.getQualifiedName(requiredType) + "'", ex);
                }
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
        }
        return (T) bean;
    }

該方法會(huì)進(jìn)入到第一個(gè)if塊中的 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null) 方法中,而 getObjectForBeanInstance 方法則會(huì)先判斷緩存是否存在,如果不存在,則進(jìn)入父類的 getObjectForBeanInstance 方法,我們看看該方法實(shí)現(xiàn):

    protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

        // Don't let calling code try to dereference the factory if the bean isn't a factory.
        if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
        }

        // Now we have the bean instance, which may be a normal bean or a FactoryBean.
        // If it's a FactoryBean, we use it to create a bean instance, unless the
        // caller actually wants a reference to the factory.
        if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
            return beanInstance;
        }

        Object object = null;
        if (mbd == null) {
            object = getCachedObjectForFactoryBean(beanName);
        }
        if (object == null) {
            // Return bean instance from factory.
            FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
            // Caches object obtained from FactoryBean if it is a singleton.
            if (mbd == null && containsBeanDefinition(beanName)) {
                mbd = getMergedLocalBeanDefinition(beanName);
            }
            boolean synthetic = (mbd != null && mbd.isSynthetic());
            object = getObjectFromFactoryBean(factory, beanName, !synthetic);
        }
        return object;
    }

首先判斷是否是 Bean 引用類型并且是否是 Factory 類型,很面向不是Bean 引用類型(Bean引用類型指的是IOC在解析XML文件 的時(shí)候,會(huì)有 ref 屬性,而這個(gè)ref 對(duì)象還沒有實(shí)例化,則暫時(shí)創(chuàng)建一個(gè)Bean引用類型的實(shí)例,用于在依賴注入的時(shí)候判斷是否是Bean的屬性類型,如果是,則從容器中取出,如果不是,則是基本類型,就直接賦值),然后進(jìn)入下面的if判斷,很明顯會(huì)直接跳過。進(jìn)入下面的 getCachedObjectForFactoryBean(beanName) 方法,從緩存中取出,很明顯,第一次肯定返回null,繼續(xù)向下,進(jìn)入if塊,重點(diǎn)在 object = getObjectFromFactoryBean(factory, beanName, !synthetic) 方法,我們進(jìn)入該方法查看:

    protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
        if (factory.isSingleton() && containsSingleton(beanName)) {
            synchronized (getSingletonMutex()) {
                Object object = this.factoryBeanObjectCache.get(beanName);
                if (object == null) {
                    object = doGetObjectFromFactoryBean(factory, beanName);
                    // Only post-process and store if not put there already during getObject() call above
                    // (e.g. because of circular reference processing triggered by custom getBean calls)
                    Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                    if (alreadyThere != null) {
                        object = alreadyThere;
                    }
                    else {
                        if (shouldPostProcess) {
                            try {
                                object = postProcessObjectFromFactoryBean(object, beanName);
                            }
                            catch (Throwable ex) {
                                throw new BeanCreationException(beanName,
                                        "Post-processing of FactoryBean's singleton object failed", ex);
                            }
                        }
                        this.factoryBeanObjectCache.put(beanName, object);
                    }
                }
                return object;
            }
        }
        else {
            Object object = doGetObjectFromFactoryBean(factory, beanName);
            if (shouldPostProcess) {
                try {
                    object = postProcessObjectFromFactoryBean(object, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
                }
            }
            return object;
        }
    }

該方法還是先重緩存中取出,然后進(jìn)入 doGetObjectFromFactoryBean(factory, beanName) 方法,我們看看該方法:

    private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
            throws BeanCreationException {

        Object object;
        try {
            if (System.getSecurityManager() != null) {
                AccessControlContext acc = getAccessControlContext();
                try {
                    object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->
                            factory.getObject(), acc);
                }
                catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            }
            else {
                object = factory.getObject();// 此處調(diào)用 ProxyFactoryBean
            }
        }
        catch (FactoryBeanNotInitializedException ex) {
            throw new BeanCurrentlyInCreationException(beanName, ex.toString());
        }
        catch (Throwable ex) {
            throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
        }

        // Do not accept a null value for a FactoryBean that's not fully
        // initialized yet: Many FactoryBeans just return null then.
        if (object == null) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(
                        beanName, "FactoryBean which is currently in creation returned null from getObject");
            }
            object = new NullBean();
        }
        return object;
    }

該方法會(huì)直接進(jìn)入 object = factory.getObject() 行,也就是 ProxyFactoryBean 的 getObject 方法,還記得我們說過,Spring 允許我們從寫 getObject 方法來實(shí)現(xiàn)特定邏輯嗎? 我們看看該方法實(shí)現(xiàn):

    public Object getObject() throws BeansException {
        initializeAdvisorChain();// 為代理對(duì)象配置Advisor鏈
        if (isSingleton()) {// 單例
            return getSingletonInstance();
        }
        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();
        }
    }

該方法很重要,首先初始化通知器鏈,然后獲取單例,這里返回的就是我們最初看到的Cglib 代理。這里的初始化過濾器鏈的重要作用就是將連接起來,基本實(shí)現(xiàn)就是循環(huán)我們在配置文件中配置的通知器,按照鏈表的方式連接起來。具體代碼各位有興趣自己去看,今天這個(gè)不是重點(diǎn)。首先判斷是否是單例,然后我們著重關(guān)注下面的方法 getSingletonInstance();

    private synchronized Object getSingletonInstance() {
        if (this.singletonInstance == null) {
            this.targetSource = freshTargetSource();
            if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
                // Rely on AOP infrastructure to tell us what interfaces to proxy.
                Class<?> targetClass = getTargetClass();
                if (targetClass == null) {
                    throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
                }
                setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
            }
            // Initialize the shared singleton instance.
            super.setFrozen(this.freezeProxy);
            this.singletonInstance = getProxy(createAopProxy());
        }
        return this.singletonInstance;
    }

該方法是同步方法,防止并發(fā)錯(cuò)誤,因?yàn)橛泄蚕碜兞俊J紫确祷匾粋€(gè)包裝過的目標(biāo)對(duì)象,然后是否含有接口,我們的目標(biāo)類沒有接口,進(jìn)入if塊,從目標(biāo)類中取出所有接口并設(shè)置接口。很明顯,并沒有什么作用,然后向下走,重要的一行是 getProxy(createAopProxy()),先創(chuàng)建AOP,再獲取代理。我們先看 crateAopProxy。

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

該方法返回一個(gè)AopProxy 類型的實(shí)例,我們看看該接口:

public interface AopProxy {
    Object getProxy();
    Object getProxy(@Nullable ClassLoader classLoader);
}

該接口定義了兩個(gè)重載方法,我們看看它有哪些實(shí)現(xiàn):

這是該接口的繼承圖,分別是 JdkDynamicAopProxy 動(dòng)態(tài)代理和 CglibAopProxy 代理。而 JdkDynamicAopProxy 實(shí)現(xiàn)了 InvocationHandler 接口,如果熟悉Java 動(dòng)態(tài)代理,應(yīng)該和熟悉該接口,實(shí)現(xiàn)了該接口的類并實(shí)現(xiàn)invoke方法,再代理類調(diào)用的時(shí)候,會(huì)回調(diào)該方法。實(shí)現(xiàn)動(dòng)態(tài)代理。

我們繼續(xù)看 createAopProxy 方法,該方法主要邏輯是創(chuàng)建一個(gè)AOP 工廠,默認(rèn)工廠是 DefaultAopProxyFactory,該類的 createAopProxy 方法則根據(jù) ProxyFactoryBean 的一些屬性來決定創(chuàng)建哪種代理:

    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.");
            }
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }

只要滿足三個(gè)條件中的其中一個(gè)就,我們看最后一個(gè)判斷,是否含有接口,沒有則返回ture,也就是說,如果目標(biāo)類含有接口,則創(chuàng)建Cglib 代理,否則則是JDK代理。最終創(chuàng)建了一個(gè) ObjenesisCglibAopProxy 代理。

我們回到 ProxyFactoryBean 類的 getProxy 方法,當(dāng) createAopProxy 返回一個(gè)Cglib 代理的后,則調(diào)用 getProxy 方法獲取一個(gè)代理對(duì)象,我們看看該方法實(shí)現(xiàn):

    @Override
    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;
            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 | 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 (Throwable ex) {
            // TargetSource.getTarget() failed
            throw new AopConfigException("Unexpected AOP exception", ex);
        }
    }

該方法基本上就是使用了Cglib 的庫的一些API最后通過字節(jié)碼生成代理類,比如 Enhancer 增強(qiáng)器,樓主對(duì)ASM 和 Cglib 也不是很熟悉,下次有機(jī)會(huì)再看詳細(xì)實(shí)現(xiàn)。總之,我們已經(jīng)知道了Spring 是如何生成代理對(duì)象的,主要的通過 ProxyFactoryBean 來實(shí)現(xiàn)。

最后,返回代理類,執(zhí)行代理類的方法。完成切面編程。

4. 總結(jié)

我們通過一個(gè)簡單的例子debug spring 源碼,了解了通過配置文件方式配置AOP的詳細(xì)過程,其中起最重要作用的還是 ProxyFactoryBean ,在定制化Bena的過程中起到了很大的作用,也提醒了我們,如果想在Spring的bean容器實(shí)現(xiàn)一些特別的功能,可以實(shí)現(xiàn) FactoryBean 接口,自定義自己的需要Bean。還有一點(diǎn),今天我們學(xué)習(xí)的例子是通過XML方式,而這個(gè)方式確實(shí)有些古老,雖然不妨礙我們學(xué)習(xí) AOP 的精髓,但我們還是希望能夠深入了解基于注解的AOP的具體實(shí)現(xiàn),也許實(shí)現(xiàn)源碼相似,但我們還是想知道到底有哪些不同,最起碼樓主在剛剛的調(diào)試中發(fā)現(xiàn)最新的SpringBoot的AOP不是基于ProxyFactroyBean實(shí)現(xiàn)的。但不要灰心,原理都是相同的。剩下的就是我們自己去挖掘。

good luck!!!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,431評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,637評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,555評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,900評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,629評(píng)論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,976評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,976評(píng)論 3 448
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,139評(píng)論 0 290
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,686評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,411評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,641評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,129評(píng)論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,820評(píng)論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,233評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,567評(píng)論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,362評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,604評(píng)論 2 380

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