spring源碼探索(4)-AOP實現原理

導讀

本篇主要針對spring aop進行源碼級解說,如有不不到位的地方敬請指出,多謝……

本文大綱如下

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

一、Spring AOP 使用姿勢

待被加強的目標類

public interface Sleepable {
    void sleep();

    void sleep2();
}

public class SleepableImpl implements Sleepable {

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

        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; 定義通知內容,也就是切入點執行前后需要做的事情 &ndash;&gt;&ndash;&gt;&ndash;&gt;-->
    <bean id="sleepAdvice2" class="com.youzan.study.spring.aop.SleepAdvice2"/>

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

    <!-- 使切入點與通知相關聯,完成切面配置 -->
    <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">
        <!-- 代理的對象,有睡覺能力 -->
        <property name="target" ref="sleepable"/>
        <!-- 使用切面 -->
        <property name="interceptorNames" value="sleepHelperAdvisor"/>
        <!-- 代理接口,睡覺接口 -->
        <property name="proxyInterfaces" value="com.youzan.study.spring.aop.Sleepable"/>
    </bean>

調用姿勢

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

1.2 配置方式

advice同配置方式一致

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

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

    <!-- 使切入點與通知相關聯,完成切面配置 -->
    <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" />

調用姿勢

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("快點睡覺!!!");
        pjp.proceed();
        System.out.println("睡著了!!!");
    }

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

這里先留一個問題,針對注解方式,我們的輸出文本順序是什么?本文結束的時候有答案,讀者可先自己嘗試思考一下。

調用姿勢和配置的方式一樣

二、Spring AOP主鏈路概覽

主要鏈路

注解方式和配置方式屬于同類,基于BeanPostProcessor,在被加強類完成實例化之后通過BeanPostProcessor進行加強。

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

aop BeanPostProcessor類圖

三、核心概念

pointCut
切入點,對什么進行加強

advice
如何增強,是具體的增強動作

advisor
通知器,集成 pointCut和advice

spring aop主要有兩種實現方式,一種是jdk的動態代理,另一種是基于cglib。

四、源碼解讀

4.1 編程方式

  1. 容器啟動的時候,會將ProxyFactoryBean的實例創建完畢

  2. 獲取代理對象
    當我們調用的時候

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

spring容器判斷ProxyFactoryBean是否創建完畢,如果創建完畢判斷是否是FacotryBean類型,如果是的話調用 ProxyFactoryBean.getObject(),這塊可以參考IOC容器部分內容,本章節不細講

下面看下ProxyFactoryBean如何getObject()

//ProxyFactoryBean
public Object getObject() throws BeansException {
    //初始化Advisor chain
    initializeAdvisorChain();
    if (isSingleton()) {
        //獲取或創建proxy 代理對象
        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對象
                    advice = this.beanFactory.getBean(name);
                }
                else {
                    // 非單例場景下創建 advisor對象
                    advice = new PrototypePlaceholderAdvisor(name);
                }

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

    this.advisorChainInitialized = true;
}

調用鏈路
|--ProxyFactoryBean.initializeAdvisorChain
|----ProxyFactoryBean.addAdvisorOnChainCreation
|------AdvisedSupport.addAdvisor
|--------AdvisedSupport.addAdvisorInternal

最后會把advisor加入到 ProxyFactoryBean的 advisors (父類AdvisedSupport的屬性 )里面,advisor的順序由用戶在spring里的配置決定。

  1. 創建Proxy對象

調用鏈路
|--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 {
    //根據 proxytargetclass或者 optimize 的配置,或者是否有接口來決策使用jdk動態代理或者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">
    <!-- 代理的對象,有睡覺能力 -->
    <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對象的創建和調用,放到下面公共部分解讀

4.2 配置方式

相對于編程式的區別,就是不需要特意指定advisor和待加強對象之前的關系。

該方式的使用需要配置一個BeanPostProcessor即DefaultAdvisorAutoProxyCreator,當待加強類Bean實例化后會進行BeanPostProcessor的加強。

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

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        //BeanPostProcessor 加強
        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 加強,DefaultAdvisorAutoProxyCreator在這里開始介入
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
}
  1. 獲取加強proxy鏈路

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

AbstractAutoProxyCreator.getAdvicesAndAdvisorsForBean 如何尋找待加強類對應的advisors呢?

//AbstractAdvisorAutoProxyCreator
protected List<Advisor> findEligibleAdvisors(Class beanClass, String beanName) {
    //獲取當前容器所有的advisors,根據Advisor接口類型進行查找
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    //獲取適合當前容器的advisors
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        //對advisor進行排序
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}
  1. advisor的排序,為什么要排序呢?如果待加強類適配的不僅僅一個advisor,那么誰先誰后呢?這基于OrderComparator進行排序,而它的實現邏輯也是基于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 {
        //尋找匹配當前類的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) {
        //讀取待加強類所有的方法,查看是否有匹配上的
        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,那么認為該類不需要加強,直接返回原生的bean實例,反之走創建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不需要進行proxy后續邏輯
    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);
        //創建 proxy對象
        Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }


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

4.3 注解方式

注解方式相比前兩種方式更為輕量,注解方式和配置方式相比編程方式對待加強類零侵入、零耦合。

注解方式原理與配置方式類似,都是基于BeanPostProcessor進行bean實例加強。但是不同的是注解方式由spring aop模塊自動向容器加入AnnotationAwareAspectJAutoProxyCreator BeanPostProcessor ,另外advisor也是程序基于代碼注解自動提取和組裝。

使用注解

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

相比<bean>標簽,對應的解析類也是不一樣的。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剛好對應 AspectJAutoProxyBeanDefinitionParser。

容器注冊AnnotationAwareAspectJAutoProxyCreator BeanPostProcessor

//AspectJAutoProxyBeanDefinitionParser
public BeanDefinition parse(Element element, ParserContext parserContext) {
    //注冊 AspectJAnnotationAutoProxyCreator
    AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
    //如果有子節點進行子節點處理,暫未用到,暫時忽略
    extendBeanDefinition(element, parserContext);
    return null;
}

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

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

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

接著在容器啟動的過程中 registerBeanPostProcessors() 進行實例化。

提取advisors
獲取加強proxy鏈路和配置方式一致,不同的在于注解方式獲取advisors是代碼自動提取的,AnnotationAwareAspectJAutoProxyCreator把AbstractAdvisorAutoProxyCreator的findCandidateAdvisors覆蓋了,有了自己的實現邏輯

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

根據加@Aspect注解的bean生成advisors的調用鏈路

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

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

    //省略一大段代碼,代碼篇幅較長,可以認為 它把spring容器中的bean都拿了出來,
    //然后判斷是否添加了 @Aspect 注解

    //根據提取出來的 @Aspect 進行進一步的組裝,獲取到具體的Advisor并添加到 advisors中返回
    List<Advisor> advisors = new LinkedList<Advisor>();
    for (String aspectName : aspectNames) {
        //從緩存中讀取已經生成的 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) 會找到所有加注解的方法
    for (Method method : getAdvisorMethods(aspectClass)) {
        Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    // 省略部分代碼,平時沒有用到這些場景,這里就不解讀了

    return advisors;
}

getAdvisorMethods方法,會把所有帶有注解的方法給提取出來,提取后會對方法進行排序,因為在后面設置advice order的時候有一個聲明順序,會起到一定的優先級影響。

//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);
            }
        }
    });
    //對方法進行排序
    Collections.sort(methods, METHOD_COMPARATOR);
    return methods;
}

方法的排序規則

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

按照上面的注解順序進行排序,如果不屬于上面的注解類型,排序統一為方法總數量。

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(可以認為是當前加了@Aspect的advice類), pointcut 就是根據注解提取出來的
    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);

    //獲取當前方法注解
    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);

    //設置advice的 聲明順序,當advice order 順序一樣的時候,該排序會有一定的影響
    springAdvice.setDeclarationOrder(declarationOrderInAspect);
    String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
    if (argNames != null) {
        springAdvice.setArgumentNamesFromStringArray(argNames);
    }
    springAdvice.calculateArgumentBindings();
    return springAdvice;
}

幾個advice類型的類圖我們看下


advice類圖

Advisor 優先級
Advisor的優先級邏輯,配置方式和注解方式一致。

我們的advisor已經生成完畢,advisor的優先級排序邏輯入口在AspectJAwareAdvisorAutoProxyCreator.sortAdvisors。

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

排序中最為關鍵的點
PartialOrder.addNewPartialComparable 這一步,將待排序的對象包裝成PartialOrder.SortObject對象,這個對象有三個屬性

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

PartialOrder.sort就是針對上面處理之后的SortObjects進行排序。

排序規則首先獲取Advisor的order,小的優先級最高,如果order一樣則取 declareOrder也就前面說的聲明順序,這里需要注意的是,聲明順序并發是和我們代碼里的屬性一致,它是經過排序的,排序邏輯向上可以找下。

當Advisor的order一樣后,排序會進入到下面的邏輯
AspectJPrecedenceComparator.comparePrecedenceWithinAspect

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

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

4.4 proxy調用解讀

本小節,三種aop使用方式的proxy創建和調用邏輯相同,所以放到一起進行講解

創建proxy創建

//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創建proxy的api調用
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

使用的是原生的jdk 動態代理api

proxy方法調用
當我們獲得到proxy之后,然后調用業務方法的時候,執行鏈路最終到了 proxy的invoke方法。

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

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

        
        
        if (chain.isEmpty()) {
            //如果chain為空,直接執行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);
            //開始執行邏輯,并返回結果
            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);
        }
    }
}

獲取當前方法的advice鏈,邏輯入口
AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice
具體實現在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();

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

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

                //判斷當前方法是否匹配當前advisor的pointcut
                if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) {
                    if (mm.isRuntime()) {
                        for (MethodInterceptor interceptor : interceptors) {
                            interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                        }
                    }
                    else {
                        //將當前advisor對應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;
}

如何根據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實例化的時候完成裝配

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

這些adapters判斷是否支持當前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);
}

現在我們獲取到了當前方法匹配的MethodInterceptor,最后也就是 MethodInterceptor chain。接下來看下具體的執行邏輯ReflectiveMethodInvocation.proceed()

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

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

jdk的動態代理就介紹到這了,cglib方式的先不介紹了,當然本篇也并非面面俱到,如果有朋友對本篇沒有提及部分感興趣的話,可以按照這個思路自己探索一番。
有興趣的朋友可以自行研究下,這里就不介紹了。

五、Spring AOP 不生效的探索

在使用spring aop的時候,可能我們會時不時的出現aop不生效的問題,最常見的莫過于spring的事務,為什么有時候不生效呢?


代理類結構內視圖

通過上面的幾個章節,這個圖大家不難理解,
前提
我們有 method A 和 methodB的兩個切面
case1:調用 C.A, 方法A切面生效
case2: 調用C.B, 方法B切面生效
case3: 調用C.A, C.A調用C.B,方法A切面生效, 方法B切面失效。
通過圖中表述,當方法A切面生效的時候,調用到 目標類C的B方法,這時候調用B的對象是目標類C而非 代理對象,所以對方法B的加強會不起作用


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

輸出內容
快點睡覺!!!
睡覺前要脫衣服!
睡覺!不休息哪里有力氣學習!
lalala
睡著了!!!
睡醒了要穿衣服!


系列文章
spring源碼探索(0)-IOC容器-架構設計
spring源碼探索(1)-IOC容器-Resource
spring源碼探索(2)-IOC容器-BeanDefinition加載與注冊
spring源碼探索(3)-IOC容器-Bean的一生
spring源碼探索(4)-AOP實現原理

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

推薦閱讀更多精彩內容