深入理解Spring IOC(五) 、 创建bean实例(上)

简介: 深入理解Spring IOC(五) 、 创建bean实例(上)

本篇我们讲上一篇中没有讲到的createBean方法,是在上一篇的代码块10中被调用这个方法,这个方法是位于AbstractAutowireCapableBeanFactory中:


代码块1
@Override
protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
    throws BeanCreationException {
  if (logger.isDebugEnabled()) {
    logger.debug("Creating instance of bean '" + beanName + "'");
  }
  // 1.这个是确保mbd的beanClass属性是有值的
  resolveBeanClass(mbd, beanName);
  try {
    // 2. 验证以及准备mbd的方法覆盖属性
    mbd.prepareMethodOverrides();
  }catch (BeanDefinitionValidationException ex) {
    throw new BeanDefinitionStoreException(mbd.getResourceDescription(),
        beanName, "Validation of method overrides failed", ex);
  }
  try {
    // 3. 这里主要是来针对代理的处理,如果是有代理之类需要替代真正bean的,就在这里返回结果了
    Object bean = resolveBeforeInstantiation(beanName, mbd);
    if (bean != null) {
      return bean;
    }
  }catch (Throwable ex) {
    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
        "BeanPostProcessor before instantiation of bean failed", ex);
  }
  // 4. 创建bean实例(这个才是真正创建bean的方法)
  Object beanInstance = doCreateBean(beanName, mbd, args);
  if (logger.isDebugEnabled()) {
    logger.debug("Finished creating instance of bean '" + beanName + "'");
  }
  return beanInstance;
}


1.1


代码块2
protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch)
      throws CannotLoadBeanClassException {
  try {
    // 如果mbd已经有beanClass,则直接结束方法
    // 返回值是类的全类名,这里一般都有的
    if (mbd.hasBeanClass()) {
      return mbd.getBeanClass();
    }
    // 这块还是和之前一样,if是特权执行,else是普通方式执行
    // 都是获取bean的全类名
    if (System.getSecurityManager() != null) {
      return AccessController.doPrivileged(new PrivilegedExceptionAction<Class<?>>() {
        @Override
        public Class<?> run() throws Exception {
          // 1.  真正解析bean的class
          return doResolveBeanClass(mbd, typesToMatch);
        }
      }, getAccessControlContext());
    } else {
      return doResolveBeanClass(mbd, typesToMatch);
    }
  } catch (PrivilegedActionException pae) {
    ClassNotFoundException ex = (ClassNotFoundException) pae.getException();
    throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
  } catch (ClassNotFoundException ex) {
    throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
  } catch (LinkageError err) {
    throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
  }
}


我们来看代码块2中的1处


代码块3
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch) throws ClassNotFoundException {
  // 此时typesToMatch是个空数组,因此if跳过去
  if (!ObjectUtils.isEmpty(typesToMatch)) {
    ClassLoader tempClassLoader = getTempClassLoader();
    if (tempClassLoader != null) {
      if (tempClassLoader instanceof DecoratingClassLoader) {
        DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
        for (Class<?> typeToMatch : typesToMatch) {
          dcl.excludeClass(typeToMatch.getName());
        }
      }
      String className = mbd.getBeanClassName();
      return (className != null ? ClassUtils.forName(className, tempClassLoader) : null);
    }
  }
  // 返回bean的全类名,返回值为mbd中的beanClass属性,也就是bean的类型
  // 注意是全类名哈
  return mbd.resolveBeanClass(getBeanClassLoader());
}


1.2


这里的prepareMethodOverrides是在AbstractBeanDefinition中:


代码块4
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
  MethodOverrides methodOverrides = getMethodOverrides();
  //  methodOverrides存在并且不是空,则准备方法覆盖
  // 都是look-up(注解为@lookup)的方法和replace-method
  if (!methodOverrides.isEmpty()) {
    for (MethodOverride mo : methodOverrides.getOverrides()) {
      prepareMethodOverride(mo);
    }
  }
}


上面的代码是你的xml必须使用look-upmethod以及replace的时候才会执行到,我们来看上面最后调用的这个prepareMethodOverride方法:


代码块5
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
  // 计算重载的方法的数量
  int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
  // 0就直接抛出异常
  if (count == 0) {
    throw new BeanDefinitionValidationException(
        "Invalid method override: no method with name '" + mo.getMethodName() +
        "' on class [" + getBeanClassName() + "]");
  // 1的话设置这个属性为true,这个属性的作用是避免掉重载的检查
  // 可以在运行的时候提高性能
  } else if (count == 1) {
    // Mark override as not overloaded, to avoid the overhead of arg type checking.
    mo.setOverloaded(false);
  }
}


1.3


这里主要是生成各种代理的,比如说当你使用Dubbo中的@Reference注解注入一个服务对象的时候,这时候就是走的这里,我们来看看它的代码:


代码块6
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
  Object bean = null;
  // 如果需要提前执行InstantiationAwareBeanPostProcessor中的postProcessBeforeInstantiation方法
  if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
    // mbd有正确的class属性 && mbd不是合成的 && 存在InstantiationAwareBeanPostProcessor(这是个特殊的BeanPostProcessor)
    if (mbd.hasBeanClass() && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      // 1.执行postProcessBeforeInstantiation方法
      bean = applyBeanPostProcessorsBeforeInstantiation(mbd.getBeanClass(), beanName);
      // 如果在这里返回了result,则执行所有的BeanPostProcessor的后置处理方法
      // 执行完了就代表一个完整的bean已经创建好
      if (bean != null) {
        bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
      }
    }
    mbd.beforeInstantiationResolved = (bean != null);
  }
  return bean;
}


我们可以看出来,这块主要是来执行InstantiationAwareBeanPostProcessor的,为什么要在代码块1.3中这里调用呢?因为要给代理类一个机会替换掉原来的对象的,因为下一步就要在代码块1.4处都要调用doCreateBean创建真正的bean实例了。然后我们来看看代码块6中的1处,其实这里便是对应着执行InstantiationAwareBeanPostProcessor


代码块7
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName)
      throws BeansException {
  // 遍历BeanPostProcessor
  for (BeanPostProcessor bp : getBeanPostProcessors()) {
    // 如果BeanPostProcessor 是个 InstantiationAwareBeanPostProcessor
    if (bp instanceof InstantiationAwareBeanPostProcessor) {
      // 强制转型
      InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
      Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
      if (result != null) {
        return result;
      }
    }
  }
  return null;
}


1.4


终于到这个doCreateBean方法了,这里才是真正创建bean的方法,也是包含逻辑最多的方法,我们不虚它,就是干,但是干之前,因为这个方法太过于复杂的原因,我先给你列个提纲,从宏观上告诉你这个方法都做了什么事情,再给你看源码,这样你就不至于很懵逼

这个doCreateBean方法,做了这些事情:1. 从工厂方法或者构造方法中二选一创建对象(取决于你的配置,这里包含的逻辑也最多,涉及到了构造方法的选择)  2. 接着是循环依赖的处理,主要是通过提前曝光的方式来处理 3. 进行属性的填充以及初始化操作,初始化中包含着bean的前置以及后置处理。

接着,我们来看看具体的代码:


代码块8
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
  // BeanWrapper是bean的包装类
  BeanWrapper instanceWrapper = null;
  if (mbd.isSingleton()) {
    // 从正在创建的factoryBean的缓存中移除(准确说其实是去拿,同时移除)
    instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
  }
  if (instanceWrapper == null) {
    // 1. 如果到这里是null,则去创建一个包含着bean实例的instanceWrapper
    instanceWrapper = createBeanInstance(beanName, mbd, args);
  }
  final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
  Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
  // 使用MergedBeanDefinitionPostProcessor修改RootBeanDefinition
  // 主要是处理@Autowired 、 @inject 、@value 标着的方法和属性
  // 从这里往后,spring 才知道是哪个方法或者是属性有这个注解
  synchronized (mbd.postProcessingLock) {
    if (!mbd.postProcessed) {
      applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
      mbd.postProcessed = true;
    }
  }
  // earlySingletonExposure是判断是否要提前曝光这个半成品的实例的,注意哈:现在的bean只是个半成品
  // 因为还没有进行属性填充,以及执行初始化方法等操作
  // mbd是单例 && 允许循环引用(默认true) && 当前bean是不是正在创建中
  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");
    }
    // 提前曝光这个beanName对应的ObjectFactory,用来解决循环引用
    addSingletonFactory(beanName, new ObjectFactory<Object>() {
      @Override
      public Object getObject() throws BeansException {
        // 2.使用SmartInstantiationAwareBeanPostProcessor返回早期bean的半成品时的引用
        // 如果没有SmartInstantiationAwareBeanPostProcessor,则直接返回bean
        // 这里返回的最终是bean本身
        return getEarlyBeanReference(beanName, mbd, bean);
      }
    });
  }
  // 初始化
  Object exposedObject = bean;
  try {
    // 3. 对bean进行属性填充
    populateBean(beanName, mbd, instanceWrapper);
    if (exposedObject != null) {
      // 4. 初始化操作
      exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
  }catch (Throwable ex) {
    if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
      throw (BeanCreationException) ex;
    }else {
      throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
    }
  }
  // 如果需要提前曝光半成品bean
  if (earlySingletonExposure) {
    Object earlySingletonReference = getSingleton(beanName, false);
    if (earlySingletonReference != null) {
      if (exposedObject == bean) {
        // 由于经过init之后的操作,earlySingletonReference和exposedObject可能不是一个实例,
        // 这里需要让他们指向一个实例,
        exposedObject = earlySingletonReference;
      // 不允许在循环依赖情况下注入原始bean && 当前bean被其他bean依赖
      }else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
        // 拿到当前bean依赖所有bean的数组
        String[] dependentBeans = getDependentBeans(beanName);
        Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
        for (String dependentBean : dependentBeans) {
          // 移除这些bean,因为这些bean依赖的bean是被增强过的bean
          if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
            // 移除失败的添加到actualDependentBeans
            actualDependentBeans.add(dependentBean);
          }
        }
        if (!actualDependentBeans.isEmpty()) {
          throw new BeanCurrentlyInCreationException(beanName,
              "Bean with name '" + beanName + "' has been injected into other beans [" +
              StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
              "] in its raw version as part of a circular reference, but has eventually been " +
              "wrapped. This means that said other beans do not use the final version of the " +
              "bean. This is often the result of over-eager type matching - consider using " +
              "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
        }
      }
    }
  }
  try {
    // 注册用于销毁的bean,
    registerDisposableBeanIfNecessary(beanName, bean, mbd);
  }catch (BeanDefinitionValidationException ex) {
    throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
  }
  return exposedObject;
}


这个doCreateBean方法,是整个spring 创建bean流程核心中的核心,当然难度也比较高,这部分代码是需要反复读的,最好你看我文章的同时还能去源码中跟一跟。这里面难度最大的方法也是这个第1处的代码(本篇也只讲这个方法,剩下的下一篇讲),这个代码创建了一个”不完整”的bean,为什么是不完整的呢?因为此时创建出来的bean还没有被进行属性填充,也就是被@Autowired以及@Resource标记的属性都还没有被注入。我们一起来看看这个方法:


代码块9
// 使用不同的策略创建bean 实例
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
  // 拿到mbd的全类名,上一篇已经说过resolveBeanClass方法
  Class<?> beanClass = resolveBeanClass(mbd, beanName);
  // beanClass不为null && beanClass是不是公共类(public修饰) && beanClass不允许访问非public的构造方法
  // 上述条件都满足就抛异常,因为都满足的话就没有构造方法可以调用了
  if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
        "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
  }
  // 如果存在factory-method,则使用factory-method创建BeanWrapper
  if (mbd.getFactoryMethodName() != null)  {
    // 1. 根据工厂方法来创建包含着bean实例的BeanWrapper实例
    return instantiateUsingFactoryMethod(beanName, mbd, args);
  }
  // resolved表示构造方法或者工厂方法已经被解析过,autowireNecessary代表是否要解析构造方法参数
  boolean resolved = false;
  boolean autowireNecessary = false;
  if (args == null) {
    synchronized (mbd.constructorArgumentLock) {
      // resolvedConstructorOrFactoryMethod不为空,说明已经解析过,resolved标为true
      if (mbd.resolvedConstructorOrFactoryMethod != null) {
        resolved = true;
        // constructorArgumentsResolved如果是true,那autowireNecessary肯定是true
        // constructorArgumentsResolved源码注释的意思是构造方法参数是否已经被解析过
        autowireNecessary = mbd.constructorArgumentsResolved;
      }
    }
  }
  // 如果已经解析过
  if (resolved) {
    // 并且是需要解析构造方法参数
    if (autowireNecessary) {
      // 2. 能走到这里的前提是你的bean是个可以被多次解析的bean,也就是prototype,
      // 事实上也只有prototype并且是个构造方法注入的resolved和autowireNecessary才都会是true
      // 原因是singleton的会被缓存,再次getbean()的话根本都走不到这里来
      return autowireConstructor(beanName, mbd, null, null);
    }else {
      // 3.使用无参数的构造方法注入
      return instantiateBean(beanName, mbd);
    }
  }
  // 去拿候选的构造方法,
  Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
  // 候选构造方法不是空 || 构造方法注入的方式 || mdb中有构造方法的参数值 || 参数不为空
  // 详细解释下这四个条件:(1)候选构造方法不是空是当注解情况下有@Autowired或@inject标着的构造器或者是你的类只有一个有参数构造
  //  或者你自己有实现了SmartInstantiationAwareBeanPostProcessor的determineCandidateConstructors方法
  // (2)是构造方法注入,(3)或者所需要的构造方法是有参的构造方法(因为某些时候我们的类只定义了一个有参构造),在或者就是
  // (4)传过来的参数不是null
  if (ctors != null ||
      mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
      mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
    // 执行构造方法注入(和2处是一个方法,只是参数不一样)
    return autowireConstructor(beanName, mbd, ctors, args);
  }
  // 使用无参数的构造方法注入
  return instantiateBean(beanName, mbd);
}



目录
相关文章
|
1天前
|
存储 Java 程序员
Spring (IoC & DI)
Spring (IoC & DI)
10 2
|
5天前
|
Java Spring 容器
Spring注解开发,bean的作用范围及生命周期、Spring注解开发依赖注入
Spring注解开发,bean的作用范围及生命周期、Spring注解开发依赖注入
14 1
Spring注解开发,bean的作用范围及生命周期、Spring注解开发依赖注入
|
5天前
|
Java 容器 Spring
Spring的加载配置文件、容器和获取bean的方式
Spring的加载配置文件、容器和获取bean的方式
14 3
Spring的加载配置文件、容器和获取bean的方式
|
5天前
|
Java Spring 容器
Spring核心概念、IoC和DI的认识、Spring中bean的配置及实例化、bean的生命周期
Spring核心概念、IoC和DI的认识、Spring中bean的配置及实例化、bean的生命周期
18 0
|
5天前
|
XML Java 数据格式
Spring框架学习 -- Bean的生命周期和作用域
Spring框架学习 -- Bean的生命周期和作用域
16 2
|
5天前
|
存储 XML Java
Spring框架学习 -- 读取和存储Bean对象
Spring框架学习 -- 读取和存储Bean对象
13 0
Spring框架学习 -- 读取和存储Bean对象
|
14天前
|
XML 前端开发 Java
【JavaEE】深入了解Spring中Bean的可见范围(作用域)以及前世今生(生命周期)
【JavaEE】深入了解Spring中Bean的可见范围(作用域)以及前世今生(生命周期)
17 0
|
14天前
|
存储 缓存 Java
【JavaEE】Spring中注解的方式去获取Bean对象
【JavaEE】Spring中注解的方式去获取Bean对象
3 0
|
14天前
|
存储 Java 对象存储
【JavaEE】Spring中注解的方式去存储Bean对象
【JavaEE】Spring中注解的方式去存储Bean对象
10 0
|
14天前
|
存储 Java 对象存储
【JavaEE】DI与DL的介绍-Spring项目的创建-Bean对象的存储与获取
【JavaEE】DI与DL的介绍-Spring项目的创建-Bean对象的存储与获取
10 0