spring源碼探索(4)-AOP實(shí)現(xiàn)原理

導(dǎo)讀

本篇主要針對(duì)spring aop進(jìn)行源碼級(jí)解說派昧,如有不不到位的地方敬請(qǐng)指出,多謝……

本文大綱如下

  1. spring aop 使用姿勢(shì)
  2. spring aop 主鏈路概覽
  3. spring aop 相關(guān)概念
  4. spring aop 源碼解讀
    4.1 編程方式解讀
    4.2 配置方式解讀
    4.3 注解方式解讀
  5. spring aop不生效的探索

一拢切、Spring AOP 使用姿勢(shì)

待被加強(qiáng)的目標(biāo)類

public interface Sleepable {
    void sleep();

    void sleep2();
}

public class SleepableImpl implements Sleepable {

    @Override
    public void sleep() {
        System.out.println("睡覺斗锭!不休息哪里有力氣學(xué)習(xí)!");

        this.sleep2();
    }

    @Override
    public void sleep2() {
        System.out.println("lalala");
    }

}
<!-- 定義被代理者 -->
<bean id="sleepable" class="com.youzan.study.spring.aop.SleepableImpl"/>

1.1 編程式

Advice

public class SleepAdvice2 implements MethodBeforeAdvice, AfterReturningAdvice {
 
    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
        System.out.println("睡覺前要脫衣服失球!");
    }
 
    public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
        System.out.println("起床后要穿衣服!");
    }
 
}
<!--&lt;!&ndash;&lt;!&ndash;&lt;!&ndash; 定義通知內(nèi)容帮毁,也就是切入點(diǎn)執(zhí)行前后需要做的事情 &ndash;&gt;&ndash;&gt;&ndash;&gt;-->
    <bean id="sleepAdvice2" class="com.youzan.study.spring.aop.SleepAdvice2"/>

    <!-- 定義切入點(diǎn)位置 -->
    <bean id="sleepPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
        <property name="pattern" value=".*sleep"/>
    </bean>

    <!-- 使切入點(diǎn)與通知相關(guān)聯(lián)实苞,完成切面配置 -->
    <bean id="sleepHelperAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
        <property name="advice" ref="sleepAdvice2"/>
        <property name="pointcut" ref="sleepPointcut"/>
    </bean>

    <!--編程方式啟用 AOP-->
    <bean id="sleepableProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!-- 代理的對(duì)象,有睡覺能力 -->
        <property name="target" ref="sleepable"/>
        <!-- 使用切面 -->
        <property name="interceptorNames" value="sleepHelperAdvisor"/>
        <!-- 代理接口烈疚,睡覺接口 -->
        <property name="proxyInterfaces" value="com.youzan.study.spring.aop.Sleepable"/>
    </bean>

調(diào)用姿勢(shì)

FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("/"+"配置文件地址");
Sleepable sleepable = (Sleepable)context.getBean("sleepableProxy");
sleepable.sleep();

1.2 配置方式

advice同配置方式一致

<!--&lt;!&ndash;&lt;!&ndash;&lt;!&ndash; 定義通知內(nèi)容黔牵,也就是切入點(diǎn)執(zhí)行前后需要做的事情 &ndash;&gt;&ndash;&gt;&ndash;&gt;-->
    <bean id="sleepAdvice2" class="com.youzan.study.spring.aop.SleepAdvice2"/>

    <!-- 定義切入點(diǎn)位置 -->
    <bean id="sleepPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
        <property name="pattern" value=".*sleep"/>
    </bean>

    <!-- 使切入點(diǎn)與通知相關(guān)聯(lián),完成切面配置 -->
    <bean id="sleepHelperAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
        <property name="advice" ref="sleepAdvice2"/>
        <property name="pointcut" ref="sleepPointcut"/>
    </bean>

    <!--配置的形式啟用 AOP-->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />

調(diào)用姿勢(shì)

Sleepable sleepable = (Sleepable)context.getBean("sleepable");
sleepable.sleep();

1.3 注解方式

Advice

@Aspect
public class SleepAdvice{

    public SleepAdvice(){

    }

    @Pointcut("execution(* *.sleep*())")
    public void sleeppoint(){}

    @Before("sleeppoint()")
    public void beforeSleep(){
        System.out.println("睡覺前要脫衣服!");
    }

    @AfterReturning("sleeppoint()")
    public void afterSleep(){
        System.out.println("睡醒了要穿衣服爷肝!");
    }


    @Around("sleeppoint()")
    public void aroundLala(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("快點(diǎn)睡覺;帧!灯抛!");
        pjp.proceed();
        System.out.println("睡著了=鹕狻!对嚼!");
    }

}
<!--注解的形式啟用 AOP-->
    <aop:aspectj-autoproxy proxy-target-class="false"/>
     <!--&lt;!&ndash;定義通知內(nèi)容夹抗,也就是切入點(diǎn)執(zhí)行前后需要做的事情&ndash;&gt;-->
    <bean id="sleepAdvice" class="com.youzan.study.spring.aop.SleepAdvice"/>

這里先留一個(gè)問題,針對(duì)注解方式纵竖,我們的輸出文本順序是什么漠烧?本文結(jié)束的時(shí)候有答案杏愤,讀者可先自己嘗試思考一下。

調(diào)用姿勢(shì)和配置的方式一樣

二已脓、Spring AOP主鏈路概覽

主要鏈路

注解方式和配置方式屬于同類珊楼,基于BeanPostProcessor,在被加強(qiáng)類完成實(shí)例化之后通過BeanPostProcessor進(jìn)行加強(qiáng)度液。

DefaultAdvisorAutoProxyCreator 和 AnnotationAwareAspectJAutoProxyCreator 都屬于BeanPostProcessor厕宗,我們看下他們的類圖

aop BeanPostProcessor類圖

三、核心概念

pointCut
切入點(diǎn)恨诱,對(duì)什么進(jìn)行加強(qiáng)

advice
如何增強(qiáng)媳瞪,是具體的增強(qiáng)動(dòng)作

advisor
通知器,集成 pointCut和advice

spring aop主要有兩種實(shí)現(xiàn)方式照宝,一種是jdk的動(dòng)態(tài)代理蛇受,另一種是基于cglib。

四厕鹃、源碼解讀

4.1 編程方式

  1. 容器啟動(dòng)的時(shí)候兢仰,會(huì)將ProxyFactoryBean的實(shí)例創(chuàng)建完畢

  2. 獲取代理對(duì)象
    當(dāng)我們調(diào)用的時(shí)候

Sleepable sleepable = (Sleepable)context.getBean("sleepableProxy");

spring容器判斷ProxyFactoryBean是否創(chuàng)建完畢,如果創(chuàng)建完畢判斷是否是FacotryBean類型剂碴,如果是的話調(diào)用 ProxyFactoryBean.getObject()把将,這塊可以參考IOC容器部分內(nèi)容,本章節(jié)不細(xì)講

下面看下ProxyFactoryBean如何getObject()

//ProxyFactoryBean
public Object getObject() throws BeansException {
    //初始化Advisor chain
    initializeAdvisorChain();
    if (isSingleton()) {
        //獲取或創(chuàng)建proxy 代理對(duì)象
        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();
    }
}
  1. Advisor chain初始化
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
    //是否已初始化
    if (this.advisorChainInitialized) {
        return;
    }

    //interceptorNames 就是spring里配置的advisor
    if (!ObjectUtils.isEmpty(this.interceptorNames)) {
        //省略部分代碼

        // Materialize interceptor chain from bean names.
        for (String name : this.interceptorNames) {
            //省略部分代碼

            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)) {
                    //從spring容器獲取 advisor對(duì)象
                    advice = this.beanFactory.getBean(name);
                }
                else {
                    // 非單例場(chǎng)景下創(chuàng)建 advisor對(duì)象
                    advice = new PrototypePlaceholderAdvisor(name);
                }

                //將advisor加入鏈中
                addAdvisorOnChainCreation(advice, name);
            }
        }
    }

    this.advisorChainInitialized = true;
}

調(diào)用鏈路
|--ProxyFactoryBean.initializeAdvisorChain
|----ProxyFactoryBean.addAdvisorOnChainCreation
|------AdvisedSupport.addAdvisor
|--------AdvisedSupport.addAdvisorInternal

最后會(huì)把a(bǔ)dvisor加入到 ProxyFactoryBean的 advisors (父類AdvisedSupport的屬性 )里面忆矛,advisor的順序由用戶在spring里的配置決定察蹲。

  1. 創(chuàng)建Proxy對(duì)象

調(diào)用鏈路
|--ProxyFactoryBean.getObject
|----ProxyFactoryBean.getSingletonInstance
|------ProxyFactoryBean.createAopProxy
|--------ProxyCreatorSupport.createAopProxy
|----------DefaultAopProxyFactory.createAopProxy
|------ProxyFactoryBean.getProxy
|--------JdkDynamicAopProxy.getProxy (或CglibAopProxy)

如何決策使用jdk還是cglib?

//DefaultAopProxyFactory
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    //根據(jù) proxytargetclass或者 optimize 的配置,或者是否有接口來決策使用jdk動(dòng)態(tài)代理或者cglib
    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()) {
            return new JdkDynamicAopProxy(config);
        }
        return CglibProxyFactory.createCglibProxy(config);
    }
    else {
        return new JdkDynamicAopProxy(config);
    }
}
<!--編程方式啟用 AOP-->
<bean id="sleepableProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    <!-- 代理的對(duì)象催训,有睡覺能力 -->
    <property name="target" ref="sleepable"/>
    <!-- 使用切面 -->
    <property name="interceptorNames" value="sleepHelperAdvisor"/>
    <!-- 代理接口洽议,睡覺接口 -->
    <property name="proxyInterfaces" value="com.youzan.study.spring.aop.Sleepable"/>
    <!--指定使用cglib-->
    <property name="optimize" value="true" />
</bean>

proxy對(duì)象的創(chuàng)建和調(diào)用,放到下面公共部分解讀

4.2 配置方式

相對(duì)于編程式的區(qū)別漫拭,就是不需要特意指定advisor和待加強(qiáng)對(duì)象之前的關(guān)系亚兄。

該方式的使用需要配置一個(gè)BeanPostProcessor即DefaultAdvisorAutoProxyCreator,當(dāng)待加強(qiáng)類Bean實(shí)例化后會(huì)進(jìn)行BeanPostProcessor的加強(qiáng)采驻。

  1. 加強(qiáng)的入口
    AbstractAutowireCapableBeanFactory#initializeBean
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
    //省略部分代碼

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        //BeanPostProcessor 加強(qiáng)
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }

    if (mbd == null || !mbd.isSynthetic()) {
        //BeanPostProcessor 加強(qiáng),DefaultAdvisorAutoProxyCreator在這里開始介入
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
}
  1. 獲取加強(qiáng)proxy鏈路

|--AbstractAutowireCapableBeanFactory.
applyBeanPostProcessorsAfterInitialization
|----AbstractAutoProxyCreator.postProcessAfterInitialization
|------AbstractAutoProxyCreator.wrapIfNecessary
|--------AbstractAutoProxyCreator.getAdvicesAndAdvisorsForBean
|--------AbstractAutoProxyCreator.createProxy
|----------ProxyFactory.getProxy
|------------DefaultAopProxyFactory.createAopProxy
|--------------JdkDynamicAopProxy.getProxy (或CglibAopProxy)

AbstractAutoProxyCreator.getAdvicesAndAdvisorsForBean 如何尋找待加強(qiáng)類對(duì)應(yīng)的advisors呢审胚?

//AbstractAdvisorAutoProxyCreator
protected List<Advisor> findEligibleAdvisors(Class beanClass, String beanName) {
    //獲取當(dāng)前容器所有的advisors,根據(jù)Advisor接口類型進(jìn)行查找
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    //獲取適合當(dāng)前容器的advisors
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        //對(duì)advisor進(jìn)行排序
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}
  1. advisor的排序礼旅,為什么要排序呢膳叨?如果待加強(qiáng)類適配的不僅僅一個(gè)advisor,那么誰先誰后呢痘系?這基于OrderComparator進(jìn)行排序,而它的實(shí)現(xiàn)邏輯也是基于advisor的order來的懒鉴。
public int compare(Object o1, Object o2) {
    boolean p1 = (o1 instanceof PriorityOrdered);
    boolean p2 = (o2 instanceof PriorityOrdered);
    if (p1 && !p2) {
        return -1;
    }
    else if (p2 && !p1) {
        return 1;
    }

    // Direct evaluation instead of Integer.compareTo to avoid unnecessary object creation.
    int i1 = getOrder(o1);
    int i2 = getOrder(o2);
    return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
}
  1. 查找匹配的advisors
//AbstractAdvisorAutoProxyCreator
protected List<Advisor> findAdvisorsThatCanApply(
            List<Advisor> candidateAdvisors, Class beanClass, String beanName) {

    ProxyCreationContext.setCurrentProxiedBeanName(beanName);
    try {
        //尋找匹配當(dāng)前類的advisor
        return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
    }
    finally {
        ProxyCreationContext.setCurrentProxiedBeanName(null);
    }
}

//真正的匹配邏輯 在 AopUtils
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
        Assert.notNull(pc, "Pointcut must not be null");
    //判斷類是否匹配
    if (!pc.getClassFilter().matches(targetClass)) {
        return false;
    }

    //獲取pointcut 的方法匹配器
    MethodMatcher methodMatcher = pc.getMethodMatcher();
    IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
    if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
        introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
    }

    Set<Class> classes = new LinkedHashSet<Class>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
    classes.add(targetClass);
    for (Class<?> clazz : classes) {
        //讀取待加強(qiáng)類所有的方法,查看是否有匹配上的
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            if ((introductionAwareMethodMatcher != null &&
                    introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
                    methodMatcher.matches(method, targetClass)) {
                return true;
            }
        }
    }

    return false;
}

如果沒有找到匹配的advisor,那么認(rèn)為該類不需要加強(qiáng)临谱,直接返回原生的bean實(shí)例璃俗,反之走創(chuàng)建proxy的鏈路。

//AbstractAutoProxyCreator
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (beanName != null && this.targetSourcedBeans.containsKey(beanName)) {
        return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }

    //判斷如果是advisor或者advice類就加入到advisedBeans中悉默,value=false城豁,表示這些bean不需要進(jìn)行proxy后續(xù)邏輯
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    //查找是否有匹配的advisor
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        //創(chuàng)建 proxy對(duì)象
        Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }


    //標(biāo)記該類不需要加強(qiáng),并返回普通的bean實(shí)例
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

4.3 注解方式

注解方式相比前兩種方式更為輕量抄课,注解方式和配置方式相比編程方式對(duì)待加強(qiáng)類零侵入唱星、零耦合。

注解方式原理與配置方式類似跟磨,都是基于BeanPostProcessor進(jìn)行bean實(shí)例加強(qiáng)间聊。但是不同的是注解方式由spring aop模塊自動(dòng)向容器加入AnnotationAwareAspectJAutoProxyCreator BeanPostProcessor ,另外advisor也是程序基于代碼注解自動(dòng)提取和組裝抵拘。

使用注解

<aop:aspectj-autoproxy proxy-target-class="false"/>

相比<bean>標(biāo)簽哎榴,對(duì)應(yīng)的解析類也是不一樣的。spring aop模塊下的spring.handlers 里指定 解析類 AopNamespaceHandler

//AopNamespaceHandler
public void init() {
    // In 2.0 XSD as well as in 2.1 XSD.
    registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
    registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
    registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

    // Only in 2.0 XSD: moved to context namespace as of 2.1
    registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}

我們使用的 aspectj-autoproxy剛好對(duì)應(yīng) AspectJAutoProxyBeanDefinitionParser僵蛛。

容器注冊(cè)AnnotationAwareAspectJAutoProxyCreator BeanPostProcessor

//AspectJAutoProxyBeanDefinitionParser
public BeanDefinition parse(Element element, ParserContext parserContext) {
    //注冊(cè) AspectJAnnotationAutoProxyCreator
    AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
    //如果有子節(jié)點(diǎn)進(jìn)行子節(jié)點(diǎn)處理尚蝌,暫未用到,暫時(shí)忽略
    extendBeanDefinition(element, parserContext);
    return null;
}

//AopNamespaceUtils
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
            ParserContext parserContext, Element sourceElement) {

    //生成AspectJAnnotationAutoProxyCreator 的beanDefinition信息并注冊(cè)到容器中充尉,
    //name=org.springframework.aop.config.internalAutoProxyCreator
    BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
            parserContext.getRegistry(), parserContext.extractSource(sourceElement));

    //對(duì) aspectj-autoproxy 的屬性進(jìn)行組裝飘言,比如proxy-target-class
    useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
    registerComponentIfNecessary(beanDefinition, parserContext);
}

接著在容器啟動(dòng)的過程中 registerBeanPostProcessors() 進(jìn)行實(shí)例化。

提取advisors
獲取加強(qiáng)proxy鏈路和配置方式一致驼侠,不同的在于注解方式獲取advisors是代碼自動(dòng)提取的姿鸿,AnnotationAwareAspectJAutoProxyCreator把AbstractAdvisorAutoProxyCreator的findCandidateAdvisors覆蓋了,有了自己的實(shí)現(xiàn)邏輯

//AnnotationAwareAspectJAutoProxyCreator
protected List<Advisor> findCandidateAdvisors() {
    //調(diào)用父類的方法倒源,檢索容器中所有的advisor
    List<Advisor> advisors = super.findCandidateAdvisors();
    //構(gòu)建加AspectJ注解的advisor
    advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    return advisors;
}

根據(jù)加@Aspect注解的bean生成advisors的調(diào)用鏈路

|--BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors
|----ReflectiveAspectJAdvisorFactory.getAdvisors
|------ReflectiveAspectJAdvisorFactory.getAdvisor
|--------new InstantiationModelAwarePointcutAdvisorImpl()
|----------InstantiationModelAwarePointcutAdvisorImpl.instantiateAdvice
|------------ReflectiveAspectJAdvisorFactory.getAdvice

//BeanFactoryAspectJAdvisorsBuilder
public List<Advisor> buildAspectJAdvisors() {
        List<String> aspectNames = null;

    //省略一大段代碼苛预,代碼篇幅較長(zhǎng),可以認(rèn)為 它把spring容器中的bean都拿了出來相速,
    //然后判斷是否添加了 @Aspect 注解

    //根據(jù)提取出來的 @Aspect 進(jìn)行進(jìn)一步的組裝,獲取到具體的Advisor并添加到 advisors中返回
    List<Advisor> advisors = new LinkedList<Advisor>();
    for (String aspectName : aspectNames) {
        //從緩存中讀取已經(jīng)生成的 advisors
        List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
        if (cachedAdvisors != null) {
            advisors.addAll(cachedAdvisors);
        }
        else {
            MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
            //具體生成advisors 的邏輯
            advisors.addAll(this.advisorFactory.getAdvisors(factory));
        }
    }
    return advisors;
}
//ReflectiveAspectJAdvisorFactory
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory maaif) {
    final Class<?> aspectClass = maaif.getAspectMetadata().getAspectClass();
    final String aspectName = maaif.getAspectMetadata().getAspectName();
    validate(aspectClass);
    final MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
            new LazySingletonAspectInstanceFactoryDecorator(maaif);

    final List<Advisor> advisors = new LinkedList<Advisor>();

    //getAdvisorMethods(aspectClass) 會(huì)找到所有加注解的方法
    for (Method method : getAdvisorMethods(aspectClass)) {
        Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    // 省略部分代碼鲜锚,平時(shí)沒有用到這些場(chǎng)景突诬,這里就不解讀了

    return advisors;
}

getAdvisorMethods方法,會(huì)把所有帶有注解的方法給提取出來芜繁,提取后會(huì)對(duì)方法進(jìn)行排序旺隙,因?yàn)樵诤竺嬖O(shè)置advice order的時(shí)候有一個(gè)聲明順序,會(huì)起到一定的優(yōu)先級(jí)影響骏令。

//ReflectiveAspectJAdvisorFactory
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
    final List<Method> methods = new LinkedList<Method>();
    ReflectionUtils.doWithMethods(aspectClass, new ReflectionUtils.MethodCallback() {
        public void doWith(Method method) throws IllegalArgumentException {
            // Exclude pointcuts
            if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
                methods.add(method);
            }
        }
    });
    //對(duì)方法進(jìn)行排序
    Collections.sort(methods, METHOD_COMPARATOR);
    return methods;
}

方法的排序規(guī)則

Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class

按照上面的注解順序進(jìn)行排序蔬捷,如果不屬于上面的注解類型,排序統(tǒng)一為方法總數(shù)量。

ReflectiveAspectJAdvisorFactory.getAdvisor

public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aif,
            int declarationOrderInAspect, String aspectName) {

    validate(aif.getAspectMetadata().getAspectClass());

    //提取 pointcut周拐,如果為空則返回null
    AspectJExpressionPointcut ajexp =
            getPointcut(candidateAdviceMethod, aif.getAspectMetadata().getAspectClass());
    if (ajexp == null) {
        return null;
    }

    //生成InstantiationModelAwarePointcutAdvisorImpl advisor铡俐, 
    //advice=aif(可以認(rèn)為是當(dāng)前加了@Aspect的advice類), pointcut 就是根據(jù)注解提取出來的
    return new InstantiationModelAwarePointcutAdvisorImpl(
            this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName);
}

getAdvice的邏輯

//ReflectiveAspectJAdvisorFactory
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut ajexp,
            MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName) {

    Class<?> candidateAspectClass = aif.getAspectMetadata().getAspectClass();
    validate(candidateAspectClass);

    //獲取當(dāng)前方法注解
    AspectJAnnotation<?> aspectJAnnotation =
            AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    if (aspectJAnnotation == null) {
        return null;
    }

    // Check 是否是 AspectJ-annotated class
    if (!isAspect(candidateAspectClass)) {
        throw new AopConfigException("Advice must be declared inside an aspect type: " +
                "Offending method '" + candidateAdviceMethod + "' in class [" +
                candidateAspectClass.getName() + "]");
    }

    //省略部分代碼

    AbstractAspectJAdvice springAdvice;

    //不同的注解類型,不同的advice
    switch (aspectJAnnotation.getAnnotationType()) {
        case AtBefore:
            springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, ajexp, aif);
            break;
        case AtAfter:
            springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, ajexp, aif);
            break;
        case AtAfterReturning:
            springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, ajexp, aif);
            //省略部分代碼
            break;
        case AtAfterThrowing:
            springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, ajexp, aif);
            AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
            //省略部分代碼
            break;
        case AtAround:
            springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, ajexp, aif);
            break;
        case AtPointcut:
            if (logger.isDebugEnabled()) {
                logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
            }
            return null;
        default:
            throw new UnsupportedOperationException(
                    "Unsupported advice type on method " + candidateAdviceMethod);
    }

    // Now to configure the advice...
    springAdvice.setAspectName(aspectName);

    //設(shè)置advice的 聲明順序妥粟,當(dāng)advice order 順序一樣的時(shí)候审丘,該排序會(huì)有一定的影響
    springAdvice.setDeclarationOrder(declarationOrderInAspect);
    String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
    if (argNames != null) {
        springAdvice.setArgumentNamesFromStringArray(argNames);
    }
    springAdvice.calculateArgumentBindings();
    return springAdvice;
}

幾個(gè)advice類型的類圖我們看下


advice類圖

Advisor 優(yōu)先級(jí)
Advisor的優(yōu)先級(jí)邏輯,配置方式和注解方式一致勾给。

我們的advisor已經(jīng)生成完畢滩报,advisor的優(yōu)先級(jí)排序邏輯入口在AspectJAwareAdvisorAutoProxyCreator.sortAdvisors捞高。

Advisor排序鏈路
|--AspectJAwareAdvisorAutoProxyCreator.sortAdvisors
|----PartialOrder.sort
|------PartialOrder.addNewPartialComparable
|--------PartialOrder.addDirectedLinks
|----------AspectJPrecedenceComparator.compare
|------------AspectJPrecedenceComparator.comparePrecedenceWithinAspect

排序中最為關(guān)鍵的點(diǎn)
PartialOrder.addNewPartialComparable 這一步夭委,將待排序的對(duì)象包裝成PartialOrder.SortObject對(duì)象灌危,這個(gè)對(duì)象有三個(gè)屬性

//advisor holder
PartialComparable object;
//比當(dāng)前advisor order 小的Advisors
List<SortObject> smallerObjects = new LinkedList<SortObject>();
//比當(dāng)前advisor order 大的Advisors
List<SortObject> biggerObjects = new LinkedList<SortObject>();

PartialOrder.sort就是針對(duì)上面處理之后的SortObjects進(jìn)行排序沛膳。

排序規(guī)則首先獲取Advisor的order裂七,小的優(yōu)先級(jí)最高屏箍,如果order一樣則取 declareOrder也就前面說的聲明順序淤堵,這里需要注意的是瞪浸,聲明順序并發(fā)是和我們代碼里的屬性一致生真,它是經(jīng)過排序的沉噩,排序邏輯向上可以找下。

當(dāng)Advisor的order一樣后柱蟀,排序會(huì)進(jìn)入到下面的邏輯
AspectJPrecedenceComparator.comparePrecedenceWithinAspect

private int comparePrecedenceWithinAspect(Advisor advisor1, Advisor advisor2) {
    
    //兩個(gè)Advisor 是否其中一個(gè)或者全部都是 after類型的Advisor
    boolean oneOrOtherIsAfterAdvice =
            (AspectJAopUtils.isAfterAdvice(advisor1) || AspectJAopUtils.isAfterAdvice(advisor2));        
    int adviceDeclarationOrderDelta = getAspectDeclarationOrder(advisor1) - getAspectDeclarationOrder(advisor2);

    if (oneOrOtherIsAfterAdvice) {
        //如果其中一個(gè)或者全部是 after類型的川蒙,先聲明的優(yōu)先級(jí)反而低
        if (adviceDeclarationOrderDelta < 0) {
            return LOWER_PRECEDENCE;
        }
        else if (adviceDeclarationOrderDelta == 0) {
            return SAME_PRECEDENCE;
        }
        else {
            return HIGHER_PRECEDENCE;
        }
    }
    else {
        //如果不是after類型的,哪個(gè)方法先聲明則擁有更高的優(yōu)先級(jí)长已。
        if (adviceDeclarationOrderDelta < 0) {
            return HIGHER_PRECEDENCE;
        }
        else if (adviceDeclarationOrderDelta == 0) {
            return SAME_PRECEDENCE;
        }
        else {
            return LOWER_PRECEDENCE;
        }
    }
}

4.4 proxy調(diào)用解讀

本小節(jié)畜眨,三種aop使用方式的proxy創(chuàng)建和調(diào)用邏輯相同,所以放到一起進(jìn)行講解

創(chuàng)建proxy創(chuàng)建

//JdkDynamicAopProxy
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);

    //原聲帶jdk創(chuàng)建proxy的api調(diào)用
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

使用的是原生的jdk 動(dòng)態(tài)代理api

proxy方法調(diào)用
當(dāng)我們獲得到proxy之后术瓮,然后調(diào)用業(yè)務(wù)方法的時(shí)候康聂,執(zhí)行鏈路最終到了 proxy的invoke方法。

調(diào)用鏈路
|--JdkDynamicAopProxy.invoke
|----AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice
|------DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice
|--------MethodBeforeAdviceAdapter.getInterceptor
|--------AfterReturningAdviceAdapter.getInterceptor
|----ReflectiveMethodInvocation.proceed
|------MethodBeforeAdviceInterceptor.invoke
|------AfterReturningAdviceInterceptor.invoke

JdkDynamicAopProxy.invoke方法

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 {
        //省略部分代碼

        //獲取當(dāng)前執(zhí)行對(duì)象匹配的advice chain
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        
        
        if (chain.isEmpty()) {
            //如果chain為空胞四,直接執(zhí)行targetd fangf 
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
        }
        else {
            // We need to create a method invocation...
            invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            //開始執(zhí)行邏輯恬汁,并返回結(jié)果
            retVal = invocation.proceed();
        }

        //省略部分代碼

        return retVal;
    }
    finally {
        if (target != null && !targetSource.isStatic()) {
            // Must have come from TargetSource.
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            // Restore old proxy.
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}

獲取當(dāng)前方法的advice鏈,邏輯入口
AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice
具體實(shí)現(xiàn)在DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice

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

    List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
    boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

    //循環(huán)當(dāng)前targetClass的advisors
    for (Advisor advisor : config.getAdvisors()) {
        if (advisor instanceof PointcutAdvisor) {
            //獲取當(dāng)前advisor的pointcut
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {

                //根據(jù)advisor獲取interceptors
                MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();

                //判斷當(dāng)前方法是否匹配當(dāng)前advisor的pointcut
                if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) {
                    if (mm.isRuntime()) {
                        for (MethodInterceptor interceptor : interceptors) {
                            interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                        }
                    }
                    else {
                        //將當(dāng)前advisor對(duì)應(yīng)interceptors 加入到 interceptorList
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                }
            }
        }else if (advisor instanceof IntroductionAdvisor) {
            IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
            if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        else {
            //如果不是上述兩種類型辜伟,則作為Interceptor 直接加入 比如 ExposeInvocationInterceptor
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }
    return interceptorList;
}

如何根據(jù)advisor獲取interceptors 氓侧?

//DefaultAdvisorAdapterRegistry
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);
    }
    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()]);
}

adapters 在DefaultAdvisorAdapterRegistry實(shí)例化的時(shí)候完成裝配

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

這些adapters判斷是否支持當(dāng)前advisor的advice,我們以MethodBeforeAdviceAdapter 為例

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

getInterceptor邏輯

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

現(xiàn)在我們獲取到了當(dāng)前方法匹配的MethodInterceptor导狡,最后也就是 MethodInterceptor chain约巷。接下來看下具體的執(zhí)行邏輯ReflectiveMethodInvocation.proceed()

public Object proceed() throws Throwable {
    //interceptors chain執(zhí)行完畢,則開始執(zhí)行target的method
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

    //MethodInterceptor chain每執(zhí)行一個(gè)旱捧,currentInterceptorIndex + 1
    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        //省略代碼独郎,本篇使用的樣例踩麦,不會(huì)走到該邏輯
    }
    else {
        // 按照 MethodInterceptor chain執(zhí)行邏輯
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

jdk的動(dòng)態(tài)代理就介紹到這了,cglib方式的先不介紹了氓癌,當(dāng)然本篇也并非面面俱到谓谦,如果有朋友對(duì)本篇沒有提及部分感興趣的話,可以按照這個(gè)思路自己探索一番顽铸。
有興趣的朋友可以自行研究下茁计,這里就不介紹了。

五谓松、Spring AOP 不生效的探索

在使用spring aop的時(shí)候星压,可能我們會(huì)時(shí)不時(shí)的出現(xiàn)aop不生效的問題,最常見的莫過于spring的事務(wù)鬼譬,為什么有時(shí)候不生效呢娜膘?


代理類結(jié)構(gòu)內(nèi)視圖

通過上面的幾個(gè)章節(jié),這個(gè)圖大家不難理解优质,
前提
我們有 method A 和 methodB的兩個(gè)切面
case1:調(diào)用 C.A竣贪, 方法A切面生效
case2: 調(diào)用C.B, 方法B切面生效
case3: 調(diào)用C.A, C.A調(diào)用C.B,方法A切面生效巩螃, 方法B切面失效演怎。
通過圖中表述,當(dāng)方法A切面生效的時(shí)候避乏,調(diào)用到 目標(biāo)類C的B方法爷耀,這時(shí)候調(diào)用B的對(duì)象是目標(biāo)類C而非 代理對(duì)象,所以對(duì)方法B的加強(qiáng)會(huì)不起作用


文章開頭的問題答案如下:

輸出內(nèi)容
快點(diǎn)睡覺E钠ぁ4醵!!
睡覺前要脫衣服!
睡覺铆帽!不休息哪里有力氣學(xué)習(xí)咆耿!
lalala
睡著了!5鳌萨螺!
睡醒了要穿衣服!


系列文章
spring源碼探索(0)-IOC容器-架構(gòu)設(shè)計(jì)
spring源碼探索(1)-IOC容器-Resource
spring源碼探索(2)-IOC容器-BeanDefinition加載與注冊(cè)
spring源碼探索(3)-IOC容器-Bean的一生
spring源碼探索(4)-AOP實(shí)現(xiàn)原理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末愧驱,一起剝皮案震驚了整個(gè)濱河市慰技,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌冯键,老刑警劉巖惹盼,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件庸汗,死亡現(xiàn)場(chǎng)離奇詭異惫确,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門改化,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掩蛤,“玉大人,你說我怎么就攤上這事陈肛∽崮瘢” “怎么了?”我有些...
    開封第一講書人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵句旱,是天一觀的道長(zhǎng)阳藻。 經(jīng)常有香客問我,道長(zhǎng)谈撒,這世上最難降的妖魔是什么腥泥? 我笑而不...
    開封第一講書人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮啃匿,結(jié)果婚禮上蛔外,老公的妹妹穿的比我還像新娘。我一直安慰自己溯乒,他們只是感情好夹厌,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著裆悄,像睡著了一般矛纹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上灯帮,一...
    開封第一講書人閱讀 52,328評(píng)論 1 310
  • 那天崖技,我揣著相機(jī)與錄音,去河邊找鬼钟哥。 笑死迎献,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的腻贰。 我是一名探鬼主播吁恍,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼播演!你這毒婦竟也來了冀瓦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤写烤,失蹤者是張志新(化名)和其女友劉穎翼闽,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體洲炊,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡感局,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年尼啡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片询微。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡崖瞭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出撑毛,到底是詐尸還是另有隱情书聚,我是刑警寧澤,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布藻雌,位于F島的核電站雌续,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏胯杭。R本人自食惡果不足惜西雀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望歉摧。 院中可真熱鬧艇肴,春花似錦、人聲如沸叁温。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)膝但。三九已至冲九,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間跟束,已是汗流浹背莺奸。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留冀宴,地道東北人灭贷。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像略贮,于是被迫代替她去往敵國(guó)和親甚疟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

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