【Spring AOP】【四】Spring AOP源码解析-AOP代理时机

1  前言

我们分析了AOP不管是XML配置还是注解方式的解析过程,这篇我们简单来说下AOP在Spring中对bean对象生命周期的一个入场时机,其实我们在讲解IOC的时候,已经点了一下这篇我们再来简单说一下。

2  源码分析

切入时机准确的说有两个地方:

  • createBean里的resolveBeforeInstantiation
  • initializeBean里的applyBeanPostProcessorsAfterInitialization

2.1  resolveBeforeInstantiation

第一个时机resolveBeforeInstantiation:

try {
    // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
    // 也就是说给当前bean的创建处理器的机会 判断当前bean能不能直接创建代理对象出来
    Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
    if (bean != null) {
        return bean;
    }
}
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    /**
     * beforeInstantiationResolved 是否在Instantiation时解析 也就是你的beanDefinition里的beforeInstantiationResolved设置为true的情况下才有可能前置处理
     */
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // Make sure bean class is actually resolved at this point.
        /**
         * mbd.isSynthetic 是否是合成的  这个跟AOP有关系 因为我看到AOP的代理里才会把这个变为true 所以我们自己的一般都是false
         * hasInstantiationAwareBeanPostProcessors 是否有实现 这个肯定有 代理的核心类本身就实现了
         */
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    Object cacheKey = getCacheKey(beanClass, beanName);
    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        // shouldSkip这里会获取所有的通知器 也就是说开始进入AOP的解析 解析有哪些通知器
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }
    // targetSource 自定义源 也就是你的bean要自己创建 要有 customTargetSourceCreators 
    // 这个我感觉有点像第三方包的意思或者自己提供创建的方法 自己创建 不走spring创建bean的生命周期
    // Create proxy here if we have a custom TargetSource.
    // Suppresses unnecessary default instantiation of the target bean:
    // The TargetSource will handle target instances in a custom fashion.
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }
    return null;
}

2.2  applyBeanPostProcessorsAfterInitialization

我们知道AOP有个核心类大哥AbstractAutoProxyCreator, 他实现了BeanPostProcessor的postProcessAfterInitialization方法,我们来看下源码:

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
        implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
        
    @Override
    // bean 初始化后置处理方法
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                // 如果需要,为 bean 生成代理对象
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    /*
      如果是基础设施类(Pointcut、Advice、Advisor 等接口的实现类),或是应该跳过的类,
      则不应该生成代理,此时直接返回 bean
      也就是代理不能给自己再加代理 就是不套娃
     */
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        // 将 <cacheKey, FALSE> 键值对放入缓存中 缓存你懂的
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }
    // 为目标 bean 查找合适的通知器
    // Create proxy if we have advice.
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    /*
      若 specificInterceptors != null,即 specificInterceptors != DO_NOT_PROXY,
      则为 bean 生成代理对象,否则直接返回 bean
     */
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 创建代理
        Object proxy = createProxy(
                bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        /*
          返回代理对象,此时 IOC 容器输入 bean,得到 proxy。此时,
          beanName 对应的 bean 是代理对象,而非原始的 bean
         */
        return proxy;
    }
    
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

以上就是创建代理对象的方法分析,过程比较简单,这里简单总结一下:

  1. 若 bean 是 AOP 基础设施类型,则直接返回
  2. 为 bean 查找合适的通知器(因为第一个时机里已经解析过并缓存了, 所以查找通知器的时候,会直接使用缓存了)
  3. 如果通知器数组不为空,说明bean需要代理,则为 bean 生成代理对象,并返回代理对象
  4. 若数组为空,则返回原始 bean即自己

3  小结

本篇我们简单了解下AOP的入场时机,接下来我们就看看AOP是如何筛选通知器的,并如何串联编排多个通知器的,休息一下,我们再继续。

posted @ 2023-02-20 07:51  酷酷-  阅读(363)  评论(0编辑  收藏  举报