Spring AOP原理-Bean是如何被AOP代理的

从 0 开始深入学习 Spring 专栏目录总览

前面我们把 Advisor 增强器的设计,以及 TargetSource 的设计都大致了解了,下面咱继续承接 48 章 2.3.3 节的内容,研究代理对象的创建流程。

前面咱已经知道,最终 bean 的初始化会被 BeanPostProcessor 的 postProcessAfterInitialization 处理,进入到 AnnotationAwareAspectJAutoProxyCreator 的 postProcessAfterInitialization 方法中,它又要调用 wrapIfNecessary 方法来尝试创建代理,咱深入方法内部来研究。

1. wrapIfNecessary

源码咱在第 48 章已经见过一次了,咱再拿出来提一下印象:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 判断决定是否是不会被增强的 bean
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // Create proxy if we have advice.
    // 如果上面的判断都没有成立,则决定是否需要进行代理对象的创建
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 创建代理对象的动作
        // 注意此处它创建了一个SingletonTargetSource,将bean包装起来了
        Object proxy = createProxy(
                bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

这里前面的筛选过滤懂还是蛮简单的,咱就不关注了,重点是关注一下中间的获取增强器,以及下面的创建代理对象,两个动作。

1.1 getAdvicesAndAdvisorsForBean

这个方法很明显是根据当前正在初始化的 bean ,去匹配获取能切入的增强器,它的源码看上去不复杂:(当然也仅仅是看上去)

protected Object[] getAdvicesAndAdvisorsForBean(
        Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    if (advisors.isEmpty()) {
        return DO_NOT_PROXY;
    }
    return advisors.toArray();
}

毫无疑问,核心逻辑是 findEligibleAdvisors 方法咯,继续往里走:

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    // 获取所有增强器
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 筛选出可以切入当前bean的增强器
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    // 添加额外的增强器
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        // 增强器排序
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

这个方法就很复杂了,尽管只有几行,但都是封装好的方法,咱一个一个的展开来看。

1.1.1 findCandidateAdvisors

又回到 AnnotationAwareAspectJAutoProxyCreator 了:

protected List<Advisor> findCandidateAdvisors() {
    // Add all the Spring advisors found according to superclass rules.
    List<Advisor> advisors = super.findCandidateAdvisors();
    // Build Advisors for all AspectJ aspects in the bean factory.
    if (this.aspectJAdvisorsBuilder != null) {
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    return advisors;
}

可以发现,这个方法只是把 SpringFramework 原生的 AOP 增强器,以及 AspectJ 形式封装的增强器都拿出来,仅此而已。

1.1.2 findAdvisorsThatCanApply

所有的增强器获取到之后,下面要去匹配可以切入到当前 bean 的增强器了,咱进入到 findAdvisorsThatCanApply 方法中:

protected List<Advisor> findAdvisorsThatCanApply(
        List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
    ProxyCreationContext.setCurrentProxiedBeanName(beanName);
    try {
        return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
    } finally {
        ProxyCreationContext.setCurrentProxiedBeanName(null);
    }
}

这个方法又交给 AopUtils 执行了,咱继续往里看:

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
    if (candidateAdvisors.isEmpty()) {
        return candidateAdvisors;
    }
    List<Advisor> eligibleAdvisors = new ArrayList<>();
    // 先匹配引介增强器
    for (Advisor candidate : candidateAdvisors) {
        if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
            eligibleAdvisors.add(candidate);
        }
    }
    boolean hasIntroductions = !eligibleAdvisors.isEmpty();
    // 再匹配普通方法增强器
    for (Advisor candidate : candidateAdvisors) {
        if (candidate instanceof IntroductionAdvisor) {
            // already processed
            continue;
        }
        if (canApply(candidate, clazz, hasIntroductions)) {
            eligibleAdvisors.add(candidate);
        }
    }
    return eligibleAdvisors;
}

可以发现,整体逻辑分为两个部分,前面是针对引介通知的增强器作筛选,后面是普通的方法通知封装的增强器。

上面的引介增强器的匹配咱就不多研究了,本来平时就用得少,咱主要还是来看对于方法的增强器,它是如何去做匹配的。进入到下面的 canApply 方法中:(留意源码中标注的注释)

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
    // 对于引介增强器,它会直接强转,使用类级别的过滤器去匹配
    if (advisor instanceof IntroductionAdvisor) {
        return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
    }
    else if (advisor instanceof PointcutAdvisor) {
        // 方法切入点的增强器匹配逻辑
        PointcutAdvisor pca = (PointcutAdvisor) advisor;
        return canApply(pca.getPointcut(), targetClass, hasIntroductions);
    }
    else {
        // It doesn't have a pointcut so we assume it applies.
        // SpringFramework也不知道咋搞了,于是就直接让它可以匹配
        return true;
    }
}

从这个逻辑中就可以看出,底层针对不同种的增强器,分别会有不同的判断逻辑。对于方法增强器的判断,它又调用了下面的重载方法:(篇幅略长,小伙伴们只需要关心有注释的部分即可)

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;
    }

    MethodMatcher methodMatcher = pc.getMethodMatcher();
    if (methodMatcher == MethodMatcher.TRUE) {
        return true;
    }

    // 针对引介通知的匹配
    IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
    if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
        introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
    }

    Set<Class<?>> classes = new LinkedHashSet<>();
    if (!Proxy.isProxyClass(targetClass)) {
        classes.add(ClassUtils.getUserClass(targetClass));
    }
    classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

    for (Class<?> clazz : classes) {
        // 逐个判断每个方法是否能被当前切入点表达式切入,切入则立即返回true
        Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
        for (Method method : methods) {
            if (introductionAwareMethodMatcher != null ?
                    introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
                    methodMatcher.matches(method, targetClass)) {
                return true;
            }
        }
    }

    return false;
}

整体思路还是很清晰的吧,我们要理解的核心部分,是下面的这个双重循环,以此就能判断出来切入点表达式是否能对当前 bean 进行增强了。

Debug 下来,最终发现可以给 OrderService 匹配到的增强器一共有 2 个:( FinanceService 就不看了,因为咱一开始学习的时候,就是拿它举的例子,所有的通知方法都切入它了)

Spring AOP原理-Bean是如何被AOP代理的

1.1.3 extendAdvisors

这个方法看上去蛮不起眼的,不过小伙伴们有自己 Debug 的话,过了这个方法会发现 eligibleAdvisors 集合中多了一个增强器:

Spring AOP原理-Bean是如何被AOP代理的

诶?它自己还有偷偷添加增强器啊,那咱看看它干了些啥:

1.1.3.1 extendAdvisors方法的小动作
protected void extendAdvisors(List<Advisor> candidateAdvisors) {
    AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}

// AspectJProxyUtils
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
    // Don't add advisors to an empty list; may indicate that proxying is just not required
    if (!advisors.isEmpty()) {
        boolean foundAspectJAdvice = false;
        for (Advisor advisor : advisors) {
            // Be careful not to get the Advice without a guard, as this might eagerly
            // instantiate a non-singleton AspectJ aspect...
            if (isAspectJAdvice(advisor)) {
                foundAspectJAdvice = true;
                break;
            }
        }
        // 发现有AspectJ包装的增强器,则添加一个ExposeInvocationInterceptor
        if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
            advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
            return true;
        }
    }
    return false;
}

逻辑不算复杂,它这个方法的关键是,判断当前可用的增强器中有没有 AspectJ 类型的,如果有的话,那就在整个增强器的列表的最前面,添加一个 ExposeInvocationInterceptor.ADVISOR 。

1.1.3.2 ADVISOR是个啥?

那这个 ADVISOR 又是个啥子?咱继续往里走:

public static final ExposeInvocationInterceptor INSTANCE = new ExposeInvocationInterceptor();

public static final Advisor ADVISOR = new DefaultPointcutAdvisor(INSTANCE) {
    @Override
    public String toString() {
        return ExposeInvocationInterceptor.class.getName() +".ADVISOR";
    }
};

哦?合着它是个对所有 bean 都生效的增强器呗?传入的这个 INSTANCE 很明显是单例的设计,那到头来核心还是这个 ExposeInvocationInterceptor 本身。

1.1.3.3 ExposeInvocationInterceptor又是个啥?

那新的问题就来了:ExposeInvocationInterceptor 这玩意的作用是什么呢?

翻开源码的核心 invoke 方法,发现它在向当前线程的 ThreadLocal 中放入了当前正在执行的代理对象的方法执行包装:

private static final ThreadLocal<MethodInvocation> invocation =
			new NamedThreadLocal<>("Current AOP method invocation");

public Object invoke(MethodInvocation mi) throws Throwable {
    MethodInvocation oldInvocation = invocation.get();
    invocation.set(mi);
    try {
        return mi.proceed();
    }
    finally {
        invocation.set(oldInvocation);
    }
}

每次都在增强器链的第一个执行,并且放入 ThreadLocal 变量中,那这意图就很明显了:它可以让后面的增强器都拿到当前正在执行的 MethodInvocation 。至于哪里会用到 MethodInvocation ,咱目前还没有遇到,后面如果遇到了咱再留意。

或许会有小伙伴产生一个小小的疑惑:那你放就放呗, MethodInvocation oldInvocation = invocation.get(); 这个操作是啥意思?原本就没有,你 get 个什么劲呢???

哎?真的没有吗?如果是一个 AOP 代理对象,调用了另外一个 AOP 代理对象的话,这个过程是在一个线程中执行的呀,那第二个代理对象的方法被调用时,是不是也会经过 ExposeInvocationInterceptor 呢?那是不是从 ThreadLocal 中就可以取出 MethodInvocation 了呢?所以小伙伴们一定要多想一层呀,多实践多思考才会更进步 ~

1.2 createProxy

上面结束之后,所有的增强器也就都准备好了,接下来就是创建代理对象的部分了,咱进入 createProxy 中:(方法略长,咱只关心关键部分的源码和注释即可)

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
        @Nullable Object[] specificInterceptors, TargetSource targetSource) {
    // 记录被代理bean的原始类型
    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }

    // 代理工厂的初始化
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.copyFrom(this);

    // 根据AOP的设计,决定是否强制使用Cglib
    if (!proxyFactory.isProxyTargetClass()) {
        if (shouldProxyTargetClass(beanClass, beanName)) {
            // Cglib动态代理直接记录被代理bean的所属类即可
            proxyFactory.setProxyTargetClass(true);
        }
        else {
            // 解析被代理bean所属类的所有实现的接口
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }

    // 1.2.1 构造整合所有增强器
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    customizeProxyFactory(proxyFactory);

    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    // 1.2.2 创建代理对象
    return proxyFactory.getProxy(getProxyClassLoader());
}

到了这里,咱就可以发现,这里面的逻辑已经基本上处理的差不多了,核心的动作就两个:收集整理要织入到目标对象的通知增强器,以及创建代理对象。前面的那些小细节小伙伴们可以自行研究,相对都是蛮简单的,小册带小伙伴们关注的是这两部分的核心逻辑。

1.2.1 buildAdvisors

源码不算长,里面有一段日志的部分,小册在这里删掉了,咱只关心核心逻辑:

protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
    // Handle prototypes correctly...
    // 这个地方是适配Spring原生AOP的MethodInterceptor,感兴趣的小伙伴可自行研究
    Advisor[] commonInterceptors = resolveInterceptorNames();

    List<Object> allInterceptors = new ArrayList<>();
    if (specificInterceptors != null) {
        allInterceptors.addAll(Arrays.asList(specificInterceptors));
        // 组合原生的方法拦截器,共同作为AOP的通知织入
        if (commonInterceptors.length > 0) {
            if (this.applyCommonInterceptorsFirst) {
                allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
            }
            else {
                allInterceptors.addAll(Arrays.asList(commonInterceptors));
            }
        }
    }
    // logger ......

    Advisor[] advisors = new Advisor[allInterceptors.size()];
    for (int i = 0; i < allInterceptors.size(); i++) {
        // 此处有一个原生AOP的适配动作
        advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
    }
    return advisors;
}

上面整合 SpringFramework 原生 AOP 的内容咱小册就不提及了,毕竟是很久之前用的东西了,咱现在都是 AspectJ 的。在最下面,它有一个 advisorAdapterRegistry.wrap 的方法调用,它是干嘛的呢?咱可以去瞅一眼:

public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
    // Advisor增强器可以直接返回
    if (adviceObject instanceof Advisor) {
        return (Advisor) adviceObject;
    }
    // 不支持非Advice的类型
    if (!(adviceObject instanceof Advice)) {
        throw new UnknownAdviceTypeException(adviceObject);
    }
    Advice advice = (Advice) adviceObject;
    // MethodInterceptor的支持
    if (advice instanceof MethodInterceptor) {
        // So well-known it doesn't even need an adapter.
        return new DefaultPointcutAdvisor(advice);
    }
    // AdvisorAdapter的支持
    for (AdvisorAdapter adapter : this.adapters) {
        // Check that it is supported.
        if (adapter.supportsAdvice(advice)) {
            return new DefaultPointcutAdvisor(advice);
        }
    }
    throw new UnknownAdviceTypeException(advice);
}

注意这个方法的参数和返回值:它可以是任意类型的入参,但返回的一定是 Advisor ,这也就呼应了 wrap 方法的含义:将可以支持转换 / 包装为 Advisor 类型的对象适配成 Advisor 。至于它可以适配的类型,内置的只有 MethodInterceptor 和几种原生的 Advice (前面 Spring 原生 AOP 中提到的),不过它提供了一个 AdvisorAdapter 的接口,供我们扩展使用,以此来支持自定义的 Advice 类型。不过我们几乎都没有这么做的,所以这部分小伙伴们知道一下就可以了,没必要深究。

1.2.2 proxyFactory.getProxy

下面就是真正创建代理对象的逻辑了,这个方法又分为两个部分:

public Object getProxy(@Nullable ClassLoader classLoader) {
    return createAopProxy().getProxy(classLoader);
}

咱一一来看。

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

private void activate() {
    this.active = true;
    for (AdvisedSupportListener listener : this.listeners) {
        listener.activated(this);
    }
}

上面有一个监听器的通知动作,由于这个动作涉及到的监听器 AdvisedSupportListener 只在 ProxyCreatorSupport 这个类中使用,咱们开发也基本不会碰这些东西,所以这个咱可以跳过了,关键的还是下面 getAopProxyFactory().createAopProxy(this); 的执行。

getAopProxyFactory 方法返回的是当前 ProxyCreatorSupport 的成员 aopProxyFactory ,借助 Debug 可以发现它的类型是 DefaultAopProxyFactory 。

Spring AOP原理-Bean是如何被AOP代理的

进入到它的 createAopProxy 方法中,终于发现了咱熟悉的 jdk 、Cglib 动态代理的字眼了:

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: " +
                    "Either an interface or a target is required for proxy creation.");
        }
        // 如果要代理的本身就是接口,或者已经是被jdk动态代理了的代理对象
        // 则使用jdk动态代理
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        // 否则使用Cglib动态代理
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        return new JdkDynamicAopProxy(config);
    }
}

至此,咱就知道,使用 jdk 动态代理,还是 Cglib 动态代理,底层的选择是在这里决定的。

1.2.2.2 AopProxy#getProxy

创建完 AopProxy 后,下面就是创建代理对象的动作了,咱以 JdkDynamicAopProxy 为例进去看一下:

public Object getProxy(@Nullable ClassLoader classLoader) {
    // logger ......
    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    // jdk动态代理的API
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

看,最底下,咱最最熟悉的 Proxy.newProxyInstance 方法出现了!!!所以由此咱就可以体会到,代理对象的底层创建还是依赖 jdk 动态代理,或者 Cglib 动态代理的核心 API 呀!

至于 Cglib 动态代理的创建,咱就不特别深入了,咱注意一下中间的核心部分即可:

    // ......
    // Configure CGLIB Enhancer...
    Enhancer enhancer = createEnhancer();
    if (classLoader != null) {
        enhancer.setClassLoader(classLoader);
        if (classLoader instanceof SmartClassLoader &&
                ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
            enhancer.setUseCache(false);
        }
    }
    enhancer.setSuperclass(proxySuperClass);
    enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
    enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
    enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));

    Callback[] callbacks = getCallbacks(rootClass);
    Class<?>[] types = new Class<?>[callbacks.length];
    for (int x = 0; x < types.length; x++) {
        types[x] = callbacks[x].getClass();
    }
    // fixedInterceptorMap only populated at this point, after getCallbacks call above
    enhancer.setCallbackFilter(new ProxyCallbackFilter(
            this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
    enhancer.setCallbackTypes(types);

    // Generate the proxy class and create a proxy instance.
    return createProxyClassAndInstance(enhancer, callbacks);
    // ......

可以看到,这也是对 Cglib 中的 Enhancer 进行操作,核心的思路是不变的,只是框架比咱考虑的更多罢了。

OK ,到此为止,代理对象也就成功创建了,整个 AOP 通知织入的流程也就结束了。

【 AOP 原理的最后一章,咱来看看实际的代理对象方法执行时,通知都是怎么执行的,它内部的调用链是如何设计的、如何调用执行的】

免责声明:
1.本站所有内容由本站原创、网络转载、消息撰写、网友投稿等几部分组成。
2.本站原创文字内容若未经特别声明,则遵循协议CC3.0共享协议,转载请务必注明原文链接。
3.本站部分来源于网络转载的文章信息是出于传递更多信息之目的,不意味着赞同其观点。
4.本站所有源码与软件均为原作者提供,仅供学习和研究使用。
5.如您对本网站的相关版权有任何异议,或者认为侵犯了您的合法权益,请及时通知我们处理。
火焰兔 » Spring AOP原理-Bean是如何被AOP代理的