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阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容