深入理解 Spring finishBeanFactoryInitialization (三)

简介: 深入理解 Spring finishBeanFactoryInitialization (三)

接着往下看,我把代码重写贴出来, 下面还有五件大事,这四件大事说完了,本文就结束了


第一: 是applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); 回调后置处理器,进行有关注解的缓存操作


第二: 是getEarlyBeanReference(beanName, mbd, bean) 获取一个提早暴露的beanDefinition对象,用于解决循环依赖问题


第三: 将刚才创建原生java对象存放一个叫singletonFactories的map中,这也是为了解决循环依赖而设计的数据结构,举个例子: 现在准备创建A实例, 然后将A实例添加到这个singletonFactories中, 继续运行发现A实例依赖B实例,于是在创建B实例,接着又发现B实例依赖A实例,于是从singletonFactories取出A实例完成装配,再将B返回给A,完成A的装配


synchronized (mbd.postProcessingLock) {
      if (!mbd.postProcessed) {
        try {
          applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
        }
        catch (Throwable ex) {
          throw new BeanCreationException(mbd.getResourceDescription(), beanName,
              "Post-processing of merged bean definition failed", ex);
        }
        mbd.postProcessed = true;
      }
    }
    // Eagerly cache singletons to be able to resolve circular references
    // even when triggered by lifecycle interfaces like BeanFactoryAware.
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
        isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
      if (logger.isDebugEnabled()) {
        logger.debug("Eagerly caching bean '" + beanName +
            "' to allow for resolving potential circular references");
      }
      // todo  重点再来看这个 addSingleFactory
      // todo  将原始对象new出来之后放到了  这个方法中的map中
      addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }
    // Initialize the bean instance.
    Object exposedObject = bean; // todo 到目前为止还是原生对象
    try {
      //todo  用来填充属性
      //设置属性,非常重要
      populateBean(beanName, mbd, instanceWrapper);
      // todo 经过AOP处理,原生对象转换成了代理对象,跟进去
      //执行后置处理器,aop就是在这里完成的处理
      exposedObject = initializeBean(beanName, exposedObject, mbd);
    }


接着看populateBean(beanName, mbd, instanceWrapper);方法,这个方法很重要,就是在这个方法中进行bean属性的装配工作,啥意思呢? 比如现在装配A实例,结果发现A实例中存在一个属性是B实例,这是就得完成自动装配的工作,源码如下:


如果仔细看,就会发现两个事:


第一: 如果不出意外,就会出现两次后置处理器的回调,第一后置处理器的回调是判断当前的bean中是否存在需要装配的属性,而第二波后置处理器的回调就是实打实的去完成装配的动作


第二: 下面的第一个处理器其实就是spring启动过程中第一个回调的处理器,只不过调用了这个处理器的不同的方法postProcessAfterInstantiation(),默认返回ture表示按照正常的流程装配对象的属性,返回false,表示不会继续装配对象中的任何属性

而我们则继续关注下面方法中的第二个后置处理器的,看看Spring是如何完成属性的自动装配的,关于这部分的跟踪,我写在下面代码的后面


protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    if (bw == null) {
      if (mbd.hasPropertyValues()) {
        throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
      }
      else {
        // Skip property population phase for null instance.
        return;
      }
    }
    // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
    // state of the bean before properties are set. This can be used, for example,
    // to support styles of field injection.
    boolean continueWithPropertyPopulation = true;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
          //todo 进行了强转, InstantiationAwareBeanPostProcessor这个接口前面说过
          // todo 只要是通过这个接口返回出来的bean Spring不在管这个bean,不给他装配任何属性
          //todo 当前这里没有用它这个变态的特性
          InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
          // todo postProcessAfterInstantiation()默认是返回true, 加上! 表示false
          if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
            continueWithPropertyPopulation = false;
            break;
          }
        }
      }
    }
    if (!continueWithPropertyPopulation) {
      return;
    }
    // todo Spring内部可以对BeanDefinition进行设置值, 参照自定义的 BeanFactory中获取到BeanDefinition.getPropertyValue().addXXX();
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    // todo 判断当前bean的解析模型是 byName 还是 byType
    // todo 再次验证了:::   当程序员直接使用@Autowired注解时, 既不是ByName 也不是ByType, 而是No
    if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
      // Add property values based on autowire by name if applicable.
      if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
        autowireByName(beanName, mbd, bw, newPvs);
      }
      // Add property values based on autowire by type if applicable.
      if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
        autowireByType(beanName, mbd, bw, newPvs);
      }
      pvs = newPvs;
    }
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
    if (hasInstAwareBpps || needsDepCheck) {
      if (pvs == null) {
        pvs = mbd.getPropertyValues();
      }
      //todo 获取出对象的所有set get方法,现在是有一个 getClass()方法,因为继承了Object, 没什么其他卵用
      PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      if (hasInstAwareBpps) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
          if (bp instanceof InstantiationAwareBeanPostProcessor) {
            pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
            if (pvs == null) {
              return;
            }
          }
        }
      }
      if (needsDepCheck) {
        checkDependencies(beanName, mbd, filteredPds, pvs);
      }
    }
    if (pvs != null) {
      applyPropertyValues(beanName, mbd, bw, pvs);
    }
  }


好,继续跟进pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(),,看看spring如何完成属性的自动装配,当然,还是那句话,如果我们直接跟进去这个方法进入的是InstantiationAwareBeanPostProcessor抽象接口抽象方法,而我们关注的是它的实现类

AutowiredAnnotationBeanDefinitionPostProcessor的实现,打上断点依次跟进


@Override
  public PropertyValues postProcessPropertyValues(
      PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    try {
      // todo 跟进来, 目的是  为 beanName 填充上属性 bean
      metadata.inject(bean, beanName, pvs);


跟进


metadata.inject(bean, beanName, pvs);


源码如下:

可以这样理解,在下面的方法中遍历当前对象中所有可能需要依赖注入的属性字段


public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    // todo 这里的  InjectedElement 表示单个的需要注入的元素对象
    Collection<InjectedElement> checkedElements = this.checkedElements;
    Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements);
    if (!elementsToIterate.isEmpty()) {
      for (InjectedElement element : elementsToIterate) {
        if (logger.isDebugEnabled()) {
          logger.debug("Processing injected element of bean '" + beanName + "': " + element);
        }
        //todo 跟进  AutowiredAnnotationBeanPostProcessor 对这个方法的实现, 在600多行处
        element.inject(target, beanName, pvs);
      }
    }
  }


跟进这个inject() 我是手动删除了这个方法中其他的很多判断,仅仅保存下来了下面我们关注的逻辑,逻辑很清楚,上面的代码中不是在遍历所有需要自动装配的field吗?如果找到了的话,就得完成自动装配,自动装配什么呢? 其实就是自动装配上当前对象依赖的其他的对象而已,因为我们使用的后置处理器是AutowireAnnotationBeanPostProcessor通过下面的代码就能得出结论就是@Autowired默认情况下是通过反射实现的自动装配


// todo 来到这里
    @Override
    protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
      Field field = (Field) this.member;
      Object value;
      value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
      if (value != null) {
        ReflectionUtils.makeAccessible(field);
        field.set(bean, value);
      }
    }
  }


我们一路往下跟进resolveDependency()我们关注这个方法如下代码:


if (instanceCandidate instanceof Class) {// todo !!!!!当运行到这行代码时, myService还没有被实例化(singletonObjects中没有) 执行完这一个行代码之后, IndexDao1完成了对myService的装配
    instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
  }


跟进这个resolveCandidate()源码如下:

很直接发现,出现的递归的现象,这其实解析清楚了Spring是如何完成属性注入的,就是只不过前前后后很多接口很多类,会扰乱这个阅读的过程


public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
    throws BeansException {
  // todo 从bean工厂的获取,  beanName = myService   requiredType = com.changwu...OrderService2 , 跟进去这个方法, 他调用了AbstractBeanFactory中的getBean(){ doGetBean();}
  return beanFactory.getBean(beanName);
}


完成装配后,其实现在的对象依然是原生的java对象 回到AbstractAutowireCapableBeanFactory中的initializeBean()方法,源码如下, 看了下面的代码就是知道了为什么applyBeanPostProcessorsBeforeInitializationinit()applyBeanPostProcessorsAfterInitialization()之间的调用顺序了

还有最后一个秘密需要揭开: Spring的AOP不是产生了代理对象? 那什么时候完成的代理呢?毕竟从我开始写这篇文章到最后都没有看到,其实AOP的实现就在下面的代码中


protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
  if (System.getSecurityManager() != null) {
    AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
      invokeAwareMethods(beanName, bean);
      return null;
    }, getAccessControlContext());
  }
  else {
    invokeAwareMethods(beanName, bean);
  }
  Object wrappedBean = bean;
  if (mbd == null || !mbd.isSynthetic()) {
    //todo 执行全部的后置处理器的 Before方法
    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
  }
  try {
    // todo 执行所有的init方法
    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()) {
    // todo 执行所有的后置处理器的 after方法
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  }
  return wrappedBean;
}


我们在前面知道当遇到这个AbstractAutoProxyCreator时,回调它的before()方法时,仅仅是标记哪些对象需要进行增强哪些对象不需增强,而没有立即生成代理对象

现在我们关注这行代码wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); ,生成代理对象的逻辑就在这里面


@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
  if (bean != null) {
    Object cacheKey = getCacheKey(bean.getClass(), beanName);
    if (!this.earlyProxyReferences.contains(cacheKey)) {
      // todo 进入
      return wrapIfNecessary(bean, beanName, cacheKey);
    }
  }
  return bean;
}


看这个方法wrapIfNecessary(bean, beanName, cacheKey);最终会进入这个实现中

大家可以看到Spring为bean生成了代理对象,默认会先检查被代理的对象有没有实现接口,如果实现了接口,就是用jdk动态代理,否则就看看有没有cglib的相关依赖,如果存在的相关依赖而没有实现接口,就会使用cglib的代理模式

另外,补充通过编码的方式控制 下面的if条件

  • config.isOptimize() -> 可以通过XMl配置, 默认false
  • config.isProxyTargetClass() -> @EnableAspectjAutoPeoxy(true) 默认也是false


@SuppressWarnings("serial")
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
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.");
    }
    if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
      //todo 目标对象是一个接口, 同样是使用jdk的动态代理
      return new JdkDynamicAopProxy(config);
    }
    return new ObjenesisCglibAopProxy(config);
  }
  else {
    // todo 所以默认使用的是 jdk的动态代理
    return new JdkDynamicAopProxy(config);
  }
}
相关文章
|
5月前
|
Java Spring
Spring中refresh分析之finishBeanFactoryInitialization方法详解
Spring中refresh分析之finishBeanFactoryInitialization方法详解
37 0
|
缓存 Java Spring
Spring IOC源码:finishBeanFactoryInitialization详解
Spring IOC源码:finishBeanFactoryInitialization详解
50 0
|
XML 缓存 Java
Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean
Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean 七千字长文深刻解读,Spirng中是如何初始化单例bean的,和面试中最常问的Spring是如何解决循环依赖?
|
缓存 Java Spring
Spring 源码学习 15:finishBeanFactoryInitialization(重点)
可以说前面的都是准备工作,而接下来开始的才是重点,在这一步会完成 BeanFactory 的初始化,同时实例化单例 Bean。 具体怎么操作的,那就一起阅读源码吧! 不过在阅读源码之前,还是需要了解一些知识的。 1. 什么是 FactoryBean ? 2. FactoryBean 是如何使用的 ? 3. Bean 是如何初始化的? 4. 常说的循环依赖是怎么解决的?
140 0
|
缓存 Java 中间件
Spring IoC源码学习:finishBeanFactoryInitialization 详解
在介绍了obtainFreshBeanFactory、invokeBeanFactoryPostProcessors、registerBeanPostProcessors 三个重要方法后,我们终于来到了最后一个重要方法:finishBeanFactoryInitialization。finishBeanFactoryInitialization是这四个方法中最复杂也是最重要的,是整个 Spring IoC 核心中的核心。
125 0
|
Java 程序员 Spring
深入理解 Spring finishBeanFactoryInitialization (二)
深入理解 Spring finishBeanFactoryInitialization (二)
124 0
|
存储 Java 程序员
深入理解 Spring finishBeanFactoryInitialization (一)
深入理解 Spring finishBeanFactoryInitialization (一)
154 0
|
Java Spring 缓存
Spring Bean生命周期-finishBeanFactoryInitialization(九)
这个方法应该是ApplicationContext刷新的时候,最重要的方法了,因为所有的bean,如果不是lazy-init的都会在这一步进行实例化,并且做一些处理。
|
8天前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
2月前
|
缓存 Java Maven
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
下一篇
无影云桌面