5-AOP——5-3 针对Bean生成动态代理

概要

过度

我们前面介绍了对<aop:aspectj-autoproxy />标签的解析过程,其实整体就做了一件事:创建一个后处理器并注册

本文我们主要介绍这个后处理器的工作原理。当然我们关注的重点是AOP相关的处理逻辑。

内容简介

结合我们之前了解的BeanFactory逻辑,了解此后处理器的工作逻辑。

对此后处理器创建AOP的逻辑进行详细分析,包括:

  1. 找出所有注册的增强器
  2. 针对要实例化的Bean选择合适增强器
  3. 利用选出的合适的增强器创建动态代理

所属环节

针对Bean生成动态代理

上下环节

上文:解析<aop:aspectj-autoproxy />节点

下文:Spring构建的动态代理对象的工作原理

源码解析

入口

我们上面讲到解析标签最终会导致AnnotationAwareAspectJAutoProxyCreator的注册,这个类的继承关系如下:

1.png

emmmm,又是一个继承关系超级复杂的类,我们不再像前面学习BeanFactory时对每个类的角色、功能一一介绍了,我们把主要注意力集中在调用上面,这样能让我们思路清晰。

这里很容易发现AbstractAutoProxyCreator继承了SmartInstantiationAwareBeanPostProcessor。这里应该对BeanPostProcessor的主要处理逻辑有实现。

在扩展中,我们对击中Bean的后处理器做了介绍。根据我们在扩展中的介绍,我们确认进行AOP动态代理创建的主要有三个地方:

  • postProcessBeforeInstantiation
  • getEarlyBeanReference
  • postProcessAfterInitialization

其中第一种情况涉及短路,第二、第三种不涉及。而第一种段路但是会继续手动调用postProcessAfterInitialization。所以实际调用的搭配方案是:

  • 1,3
  • 2,3

我们依次介绍三个调用方法,最后再整合看。我们先介绍一下基本的数据结构,方便后续代码理解:

基础数据结构

// 这个里面存的是通过 TargetSourceCreator 创建的 Bean 实例,不走 Spring 的创建实例、填值、初始化、提前暴露啥的,直接
// 一步走到最后的调用初始化之后的后处理器
private final Set<String> targetSourcedBeans = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
// 这个是配合 BeanFactory 进行解决循环依赖时提供的
// key: 计算得到的 cacheKey
// value: 是完成创建实例后得到的地址。还没进行填值、初始化啥的
private final Map<Object, Object> earlyProxyReferences = new ConcurrentHashMap<>(16);
// 这个是将已经完成代理创建的对象进行缓存
// key: 计算得到的cacheKey
// value: 代理之后得到的 Class
private final Map<Object, Class<?>> proxyTypes = new ConcurrentHashMap<>(16);
// 已经增强的 Bean 的 map ,key 是根据 beanName 生成的。 value 是这个 bean 已经增强的原因:
// False 表示经过之前的判断,此 Bean 不需要增强。
// True 表示经过之前的判断,此 Bean 需要增强
private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);

四个属性。

前两个属性分别对应postProcessBeforeInstantiationgetEarlyBeanReference的实现。

后两个属性是做缓存以加快执行效率。

postProcessBeforeInstantiation

我们先上代码:

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
  Object cacheKey = getCacheKey(beanClass, beanName);

  // TODO targetSourcedBeans 中没有针对这个 Bean 的缓存??????
  if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
    if (this.advisedBeans.containsKey(cacheKey)) {//TODO 之前对此类 Bean 做过判断
      return null;
    }
    // 1. AOP配置的基础类【不需进行AOP】
    // 2. 子类自行定义一个判断条件,将自己不想进行代理的类摘出去
    if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
      this.advisedBeans.put(cacheKey, Boolean.FALSE); // 将这次做的判断进行缓存,方便下次处理时判断
      return null;
    }
  }

  // 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.
  // 这里看一下,我们是不是配置了对应的 TargetSourceCreator 来生成此类实例,如果配置了的话就直接走配置生成可用的目标实例
  // 缓存创建的实例,然后在这里创建完成代理,不再走 Spring 的创建实例、属性填充、初始化啥的操作了
  //
  // 这里主要是提供给使用者一个短路 Spring 基础流程的机会,方便进行定制
  TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
  if (targetSource != null) {
    // 存起来,表示下次处理 beanName ,直接走  TargetSourceCreator 并创建代理
    if (StringUtils.hasLength(beanName)) {
      this.targetSourcedBeans.add(beanName);
    }
    // 得到我们配置的 Advisor
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
    // 根据我们配置的 Advisor 创建代理对象
    Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
    // TODO 缓存一下我们创建的代理类【这里不清楚有啥用】
    this.proxyTypes.put(cacheKey, proxy.getClass());
    return proxy;// 短路
  }

  return null;
}


protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {
  // We can't create fancy target sources for directly registered singletons.
  if (this.customTargetSourceCreators != null &&
      this.beanFactory != null && this.beanFactory.containsBean(beanName)) {
    for (TargetSourceCreator tsc : this.customTargetSourceCreators) {
      TargetSource ts = tsc.getTargetSource(beanClass, beanName);
      if (ts != null) {
        // Found a matching TargetSource.
        if (logger.isDebugEnabled()) {
          logger.debug("TargetSourceCreator [" + tsc +
                       "] found custom TargetSource for bean with name '" + beanName + "'");
        }
        return ts;
      }
    }
  }

  // No custom TargetSource found.
  return null;
}

思路如下:

2.png

上面的思路是有点乱的,你只需要明白一点就可以了,这个函数的职责是尝试借助TargetSourceCreator完成实例构建,如果可以就可以短路操作,如果不行就走正常创建。这里面的一大堆判断也是在推断这个 Bean 是否之前做过这种判断,有没有保存好的判断结果

有两个函数里封装了我们的核心操作:

  • getAdvicesAndAdvisorsForBean
  • createProxy

职责我们大概能猜到,具体的实现思路我们后面统一介绍。

getEarlyBeanReference

先上代码:

@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
  Object cacheKey = getCacheKey(bean.getClass(), beanName);
  this.earlyProxyReferences.put(cacheKey, bean); // 这里的 Bean 是完成创建实例后得到的地址。还没进行填值、初始化啥的
  return wrapIfNecessary(bean, beanName, cacheKey);
  //TODO 这里提前进行了包装,如果是jdk动态代理,后面在注入时怎么玩????,看看代理之后会不会影响 getter/setter函数
}

这里思路很简单,因为实例已经存在了,所以我们做缓存,然后根据情况创建代理即可。其中wrapIfNecessary方法后面详细介绍。

postProcessAfterInitialization

贴代码:

/**
     * Create a proxy with the configured interceptors if the bean is
     * identified as one to proxy by the subclass.
     *
     * @see #getAdvicesAndAdvisorsForBean
     */
// 如果要处理的 bean 实例被子类标识为需要代理的,就通过配置的拦截器创建代理
//
// 注意,这里的用词是拦截器,因为是通过回调完成的调用。过滤器 Filter 是和 servlet 容器切合到一起的,
// 是 tomcat 的东西
//
// 这里是将通过 Spring 创建实例、完成添值、初始化完成的对象实例或者前面postProcessBeforeInstantiation()短路
// 得到的完善的实例,在这里将需要进行代理的进行创建代理
//
// 注意,这里需要判断是否已经代理过,别在 postProcessBeforeInstantiation() 创建一次代理,这里再创建一次
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
  if (bean != null) {
    // TODO 这里后面重新过一下 Spring 创建 Bean 实例的步骤,传进来的 beanName 是 alias 还是带 & 的还是单纯的 beanId
    // TODO 如果不是单纯的 beanId ,这里可能会出错
    Object cacheKey = getCacheKey(bean.getClass(), beanName);
    // 这里意味着前面通过这个提前拿到的地址。在调用 postProcessAfterInitialization() 包裹时发现传进来的
    // 已经和最开始的不一样了。那就重新根据情况看是否要创建代理
    // TODO 这里能看出来和最开始暴露出去的不一样了,估计解决循环依赖是否成功只有依赖一下两种情况是否恰好发生:
    // 1. 没有任何 Bean 引用了提前暴露出去的Bean
    // 2. 在后面的 getEarlyBeanReference() 的处理过程中有操作继续包裹导致这里的不一致
    // TODO 其实这里想多了,上面的都是建立在假设 earlyProxyReferences 就是暴露出去的对象,但是这里可以把它理解成一个记录是否提前创建代理的记录
    if (this.earlyProxyReferences.remove(cacheKey) != bean) {
      return wrapIfNecessary(bean, beanName, cacheKey);
    }
  }
  return bean;
}

思路很简单,还是委托给wrapIfNecessary根据情况创建代理。只是之前可能做了提前暴露,用earlyProxyReferences缓存协助判断看能否少走一步,加快构造速度。

动态代理创建内部逻辑记录

wrapIfNecessary

上面我们对三个后处理的钩子做了一些介绍,最后我们发现动态代理的创建基本委托给了wrapIfNecessary,当然也有更细致的委托,这里我们从这里入手对动态代理介绍,根据我先撸过一次的经验来说,从这里入手会把上面依赖的函数都过一遍。

直接放代码:

// 如果这个 Bean 需要被代理,就代理一下
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
  // this.targetSourcedBeans.contains(beanName) 表示此 beanName 对应的 bean 没有走正经 Spring 创建实例的过程
  // 直接搞定了。
  // TODO 这种创建方式貌似不走AOP的东西
  if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
    return bean;
  }
  // 此 cacheKey 【通过 bean 实例得出】 之前做过判断,根据之前的判断是不用代理的
  if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
    return bean;
  }
  // 如果满足以下条件,则不对 bean 进行代理
  // 1. 此类是基础类【配置代理相关的配置类】
  // 2. 或者根据用户自定义的逻辑,不对它进行代理
  if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
    this.advisedBeans.put(cacheKey, Boolean.FALSE);// 这里做了缓存,方便有重复判断时加快速度
    return bean;
  }

  // Create proxy if we have advice.
  // 得到 bean 对应的增强方法,如果有需要增强的方法,则创建代理
  Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
  if (specificInterceptors != DO_NOT_PROXY) {
    this.advisedBeans.put(cacheKey, Boolean.TRUE);// 直接放进去,方便后续判断
    // 已经确定要创建代理,将创建工作进行委托
    Object proxy = createProxy(
      bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    // TODO 看一下这个缓存是怎么做的??代理临时生成的类可以复用吗??
    this.proxyTypes.put(cacheKey, proxy.getClass());
    return proxy;
  }
  // 已经确定不用创建代理,缓存一下结果,方便后面的判断
  this.advisedBeans.put(cacheKey, Boolean.FALSE);
  return bean;
}

思路如下:

3.png

我们主要介绍两个函数即可:

  • getAdvicesAndAdvisorsForBean
  • createProxy

正好是我们最开始的postProcessBeforeInstantiation依赖的两个。

getAdvicesAndAdvisorsForBean

直接上代码:

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

  // 继续委托
  List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
  // 如果没查到就返回特定值,方便判断
  // TODO 感觉这种设计方法还是不太好的,一个返回值有了多种解读语意,应该是 Spring 为了接口简洁做的一些妥协
  if (advisors.isEmpty()) {
    return DO_NOT_PROXY;
  }
  return advisors.toArray();
}

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
  // 获得所有的增强器
  // 找出来,然后实例化
  List<Advisor> candidateAdvisors = findCandidateAdvisors();
  // 找到这个 bean 可以用的增强
  // 这里涉及针对 aop 筛选类、方法的东西
  List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
  // 这里留一个钩子,方便子类根据自己的需要进行增强器定制
  extendAdvisors(eligibleAdvisors);
  if (!eligibleAdvisors.isEmpty()) {
    eligibleAdvisors = sortAdvisors(eligibleAdvisors);
  }
  return eligibleAdvisors;
}

还是老套路,继续向外委托,本函数只做基础的记录和转换。所以就一下子贴了两个函数上去。整体思路还是比较清楚的:

  1. 先拿到所有的增强器
  2. 根据Bean筛选出可用的增强器
  3. 返回

我们接下来依次看这两步的操作,先看第一步:拿到所有的增强器

// 返回 auto-proxy 中配置的所有的增强器
protected List<Advisor> findCandidateAdvisors() {
  Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
  // 委托给专门负责增强器检索的类
  return this.advisorRetrievalHelper.findAdvisorBeans();
}

我们看findAdvisorBeans:

// 找到当前 BeanFactory 中所有的增强器
// TODO 注意,因为声明增强器的方法太多了,我们挑通用逻辑。
// 不支持 FactoryBean。。。。正常人打@Aspect注解也不会专门搞个 FactoryBean , 保持类的功能纯粹吧
// TODO 不支持正在实例化的bean。。。。这个再看
public List<Advisor> findAdvisorBeans() {
  // Determine list of advisor bean names, if not cached already.
  String[] advisorNames = this.cachedAdvisorBeanNames;
  if (advisorNames == null) {
    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let the auto-proxy creator apply to them!
    // 得到实现了 Advisor 接口的所有 beanId
    // 注意,这里传了 false ,不会对 FactoryBean 进行初始化后再比
    // TODO  存疑,我们打的是 @Aspect 注解,什么时候转化成对应的 Advisor 类型的Bean了
    advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
      this.beanFactory, Advisor.class, true, false);
    this.cachedAdvisorBeanNames = advisorNames;
  }
  // 没有定义增强器,直接返回
  if (advisorNames.length == 0) {
    return new ArrayList<>();
  }

  List<Advisor> advisors = new ArrayList<>();
  for (String name : advisorNames) {
    if (isEligibleBean(name)) {
      // 等等,这个注意了,不是还没初始化的 Bean ,是正在初始化的。想一下,有没有什么问题?
      // TODO 是不是为了避免循环依赖???毕竟这里是配置类,如果配置类依赖了马上要代理的单例(或者其他)类,解决循环依赖肯定是要失败的吧
      // 所以,这里快刀斩乱麻,直接把这种危险依赖过滤掉了。鸡贼啊
      if (this.beanFactory.isCurrentlyInCreation(name)) {
        if (logger.isDebugEnabled()) {
          logger.debug("Skipping currently created advisor '" + name + "'");
        }
      } else {
        try {
          // 都是创建好的或者还没开始创建的,把他们实例化然后收集起来
          advisors.add(this.beanFactory.getBean(name, Advisor.class));
        } catch (BeanCreationException ex) {
          Throwable rootCause = ex.getMostSpecificCause();
          if (rootCause instanceof BeanCurrentlyInCreationException) {
            BeanCreationException bce = (BeanCreationException) rootCause;
            String bceBeanName = bce.getBeanName();
            if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
              if (logger.isDebugEnabled()) {
                logger.debug("Skipping advisor '" + name +
                             "' with dependency on currently created bean: " + ex.getMessage());
              }
              // Ignore: indicates a reference back to the bean we're trying to advise.
              // We want to find advisors other than the currently created bean itself.
              continue;
            }
          }
          throw ex;
        }
      }
    }
  }
  return advisors;
}

整体思路比较简单,就是找出了BeanFactory中配置的所有的Advisor,然后实例化返回。

接下来看第二步:根据Bean筛选出可用的增强器

// 检索增强器列表,找出所有可以用于 bean 代理的增强器
protected List<Advisor> findAdvisorsThatCanApply(
  List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
  // 使用 ThreadLocal 保存此线程正在生成代理的目标 beanId ,应该是为了监控及防止死循环吧
  ProxyCreationContext.setCurrentProxiedBeanName(beanName);
  try {
    // 老套路,处理完信息记录、条件验证之后,将要干的活委托给专门干这个活的人
    return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
  } finally {
    // 清除之前存储的 beanId
    ProxyCreationContext.setCurrentProxiedBeanName(null);
  }
}

我们继续深入看详细的实现思路:

// 从入参的增强器列表中筛出入参的class可用的
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
  if (candidateAdvisors.isEmpty()) { // 没得选,就返回空
    return candidateAdvisors;
  }
  List<Advisor> eligibleAdvisors = new ArrayList<>();
  for (Advisor candidate : candidateAdvisors) {
    //IntroductionAdvisor 判断
    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;
    }
    // 非 IntroductionAdvisor 判断是否可用
    if (canApply(candidate, clazz, hasIntroductions)) {
      eligibleAdvisors.add(candidate);
    }
  }
  return eligibleAdvisors;
}

这里分了两种判断,很简单,因为Advisor分两种:

  • IntroductionAdvisor只判断到类级别
  • PointcutAdvisor判断到方法级别

有兴趣可以深入去看,不过根据猜测,我们用到的应该都是第二种。

到这里,我们找出了所有可用的增强器。

createProxy

上面我们筛选出了合适的增强器,现在开始根据增强器构建动态代理。

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

  //这里应该是把代理处理之前的类进行保存
  if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
    AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
  }

  ProxyFactory proxyFactory = new ProxyFactory(); // 创建 ProxyFactory ,后面将用此对象通过传进去的信息决定 JDK/CGLIB 的选择
  proxyFactory.copyFrom(this);

  if (!proxyFactory.isProxyTargetClass()) { // 只有在没有设置必须使用 CGLib 时才根据什么 BD字段、BD指定Class的接口进行判断
    if (shouldProxyTargetClass(beanClass, beanName)) {
      proxyFactory.setProxyTargetClass(true);
    } else {
      evaluateProxyInterfaces(beanClass, proxyFactory);
    }
  }

  Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
  proxyFactory.addAdvisors(advisors);
  proxyFactory.setTargetSource(targetSource);
  // 一个钩子,方便定制
  customizeProxyFactory(proxyFactory);

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

  return proxyFactory.getProxy(getProxyClassLoader()); // 代理的创建和获取
}

我们在这个函数主要根据Bean实例的情况和配置进行判断,并将判断的结果设置到proxyFactory中,具体的创建操作委托给了proxyFactory

其实最关键的,这里做了一个判断,设置了两个属性:

  • 判断了创建代理的方式:CGLib还是JDK。
  • 设置了代理的目标实例,设置了动态代理的切面逻辑——增强器列表。

如果强制使用CGLib就直接使用,否则根据实例实现的接口判断能否使用JDK:

protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
  // 得到此类实现的所有接口
  Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
  boolean hasReasonableProxyInterface = false;
  // 筛选一下接口,看有没有可以用来代理的,如果有就可以考虑 JDK 动态代理了。如果没有只能走 CGLIB
  for (Class<?> ifc : targetInterfaces) {

    // 1. 不能是那些 Spring 容器回调的接口
    // 2. 不能是那些本地链接库的
    // 3. 接口不能是空的
    if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&
        ifc.getMethods().length > 0) {
      hasReasonableProxyInterface = true;
      break;
    }
  }
  // 如果有符合条件的,就都存起来
  // TODO 这里没有专门筛选那些,看看后面根据存的接口使用时有没有过滤
  // TODO 感觉这里做的不是特别好
  if (hasReasonableProxyInterface) {
    // Must allow for introductions; can't just set interfaces to the target's interfaces only.
    for (Class<?> ifc : targetInterfaces) {
      proxyFactory.addInterface(ifc);
    }
  } else {
    // 没有符合条件的接口,直接设置用 CGLIB 生成代理
    proxyFactory.setProxyTargetClass(true);
  }
}

这里整体的判断思路还是比较清晰的。

至此,我们就把配置都设置到proxyFactory了,接下来我们看一下proxyFactory创建动态代理的策略。

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

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

这里直接委托给了AopProxyFactory,我们继续深入:

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
  // 如果有特殊配置或者类的情况要求用 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() || Proxy.isProxyClass(targetClass)) {
      // 配置不合理,按照实际情况决定用 JDK 动态代理
      return new JdkDynamicAopProxy(config);
    }
    return new ObjenesisCglibAopProxy(config); // 否则根据配置用 CGLIB 动态代理
  } else { // 默认用 JDK 动态代理
    return new JdkDynamicAopProxy(config);
  }
}

思路很顺畅,至此我们根据配置和具体的信息得到了一个JdkDynamicAopProxy或者一个ObjenesisCglibAopProxy

他们的工作原理下文会进行介绍。

扩展

Bean 后处理器相关介绍

BeanPostProcessor

提供了两个针对Bean的处理钩子,在调用初始化钩子前后进行调用。

postProcessBeforeInitialization

调用场景:Bean填充属性完成,在initializeBean()方法中先调用这个,再调用初始化的函数

返回结果:返回加工结果,如果返回null,后面的postProcessBeforeInitialization就不再调用了【同时,此后处理器返回的也不再被使用】

postProcessAfterInitialization:后处理器方法,可以在这里进行代理创建

调用场景:在initializeBean()方法中调用初始化的函数完成

返回结果:返回加工结果,如果返回null,后面的postProcessAfterInitialization就不再调用了【同时,此后处理器返回的也不再被使用】

InstantiationAwareBeanPostProcessor

继承自上面的接口,新增两个后处理钩子用于在创建实例前后调用。

postProcessBeforeInstantiation:后处理器方法, 可以在这里直接创建出实例并完成代理创建,这里会阻塞后面的几乎所有操作【创建实例/依赖注入/初始化】(阻塞我们介绍的那一大串的正常创建Bean的逻辑)

调用场景:在createBean()方法中调用,没有返回结果才委托给doCreateBean()

返回结果:返回加工结果,如果返回结果不是null,后面的流程被全部绕过,直接调用postProcessAfterInitialization,然后返回 Bean 实例

postProcessAfterInstantiation

调用场景:走正常的创建逻辑,在创建完实例之后、填值之前调用

返回结果:返回加工结果,如果返回结果是false,不再继续调用,且不再继续调用填值操作

postProcessPropertyValues: 处理的主题不是 Bean 实例

调用场景:调用完上面的后处理器,找到合适的属性值之后调用这个方法对值进行处理

返回结果:返回加工结果,如果返回结果是null,不再使用此属性值进行属性填充

SmartInstantiationAwareBeanPostProcessor

继承自上买呢的接口,增加了用来预测创建 bean 的返回实例类型的方法。

predictBeanType:预测 Bean 的Class,感觉不是很重要的地方

determineCandidateConstructors:决定使用 bean 的构造函数,不再深入

getEarlyBeanReference:获得 bean 的提前引用,用来解决循环引用,可以在这里进行代理创建

调用场景:创建实例完成,是单例,需要先暴露实例以解决循环依赖再进行填值。调用此后处理器处理之后再暴露。

返回结果:返回加工结果,默认返回原对象。

问题遗留

参考文献

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容