返回介绍

5.7.1 创建 bean 的实例

发布于 2025-04-22 22:09:11 字数 17410 浏览 0 评论 0 收藏

当我们了解了循环依赖以后就可以深入分析创建 bean 的每个步骤了,首先我们从 createBeanInstance 开始。

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {

 //解析 class

  Class beanClass = resolveBeanClass(mbd, beanName);

  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());

 }

 //如果工厂方法不为空则使用工厂方法初始化策略

  if (mbd.getFactoryMethodName() != null) {

   return instantiateUsingFactoryMethod(beanName, mbd, args);

 }

  // Shortcut when re-creating the same bean...

  boolean resolved = false;

  boolean autowireNecessary = false;

  if (args == null) {

   synchronized (mbd.constructorArgumentLock) {

   //一个类有多个构造函数,每个构造函数都有不同的参数,所以调用前需要先根据参数锁定

   构造函数或对应的工厂方法

    if (mbd.resolvedConstructorOrFactoryMethod != null) {

     resolved = true;

     autowireNecessary = mbd.constructorArgumentsResolved;

   }

  }

 }

 //如果已经解析过则使用解析好的构造函数方法不需要再次锁定

  if (resolved) {

   if (autowireNecessary) {

   //构造函数自动注入

    return autowireConstructor(beanName, mbd, null, null);

  }

   else {

   //使用默认构造函数构造

    return instantiateBean(beanName, mbd);

  }

 }

 //需要根据参数解析构造函数

  Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);

  if (ctors != null ||

    mbd.getResolvedAutowireMode() == RootBeanDefinition. AUTOWIRE_

   CONSTRUCTOR ||

    mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {

  //构造函数自动注入

   return autowireConstructor(beanName, mbd, ctors, args);

 }

 //使用默认构造函数构造

  return instantiateBean(beanName, mbd);

}

虽然代码中实例化的细节非常复杂,但是在 createBeanIntance 方法中我们还是可以清晰地看到实例化的逻辑的。

(1)如果在 RootBeanDefinition 中存在 factoryMethodName 属性,或者说在配置文件中配置了 factory-method,那么 Spring 会尝试使用 instantiateUsingFactoryMethod(beanName, mbd, args) 方法根据 RootBeanDefinition 中的配置生成 bean 的实例。

(2)解析构造函数并进行构造函数的实例化。因为一个 bean 对应的类中可能会有多个构造函数,而每个构造函数的参数不同,Spring 在根据参数及类型去判断最终会使用哪个构造函数进行实例化。但是,判断的过程是个比较消耗性能的步骤,所以采用缓存机制,如果已经解析过则不需要重复解析而是直接从 RootBeanDefinition 中的属性 resolvedConstructorOrFactoryMethod 缓存的值去取,否则需要再次解析,并将解析的结果添加至 RootBeanDefinition 中的属性 resolvedConstructorOrFactoryMethod 中。

1.autowireConstructor

对于实例的创建 Spring 中分成了两种情况,一种是通用的实例化,另一种是带有参数的实例化。带有参数的实例化过程相当复杂,因为存在着不确定性,所以在判断对应参数上做了大量工作。

public BeanWrapper autowireConstructor(

final String beanName, final RootBeanDefinition mbd, Constructor[]

chosenCtors, final Object[] explicitArgs) {

  BeanWrapperImpl bw = new BeanWrapperImpl();

 this.beanFactory.initBeanWrapper(bw);

  Constructor constructorToUse = null;

  ArgumentsHolder argsHolderToUse = null;

  Object[] argsToUse = null;

 //explicitArgs 通过 getBean 方法传入

 //如果 getBean 方法调用的时候指定方法参数那么直接使用

  if (explicitArgs != null) {

   argsToUse = explicitArgs;

  }else {

  //如果在 getBean 方法时候没有指定则尝试从配置文件中解析

   Object[] argsToResolve = null;

  //尝试从缓存中获取

   synchronized (mbd.constructorArgumentLock) {

    constructorToUse = (Constructor) mbd.resolvedConstructorOrFactoryMethod;

    if (constructorToUse != null && mbd.constructorArgumentsResolved) {

    //从缓存中取

     argsToUse = mbd.resolvedConstructorArguments;

     if (argsToUse == null) {

     //配置的构造函数参数

      argsToResolve = mbd.preparedConstructorArguments;

    }

   }

  }

  //如果缓存中存在

   if (argsToResolve != null) {

   //解析参数类型,如给定方法的构造函数 A(int,int) 则通过此方法后就会把配置中的

   ("1","1") 转换为(1,1)

   //缓存中的值可能是原始值也肯能是最终值

    argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse,

   argsToResolve);

  }

 }

 //没有被缓存

  if (constructorToUse == null) {

   // Need to resolve the constructor.

   boolean autowiring = (chosenCtors != null ||

    mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_

   CONSTRUCTOR);

   ConstructorArgumentValues resolvedValues = null;

   int minNrOfArgs;

   if (explicitArgs != null) {

    minNrOfArgs = explicitArgs.length;

   }else {

   //提取配置文件中的配置的构造函数参数

    ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();

   //用于承载解析后的构造函数参数的值

    resolvedValues = new ConstructorArgumentValues();

   //能解析到的参数个数

    minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs,

   resolvedValues);

  }

   // Take specified constructors, if any.

   Constructor[] candidates = chosenCtors;

   if (candidates == null) {

    Class beanClass = mbd.getBeanClass();

    try {

     candidates = (mbd.isNonPublicAccessAllowed() ?

    beanClass.getDeclaredConstructors():beanClass.

    getConstructors());

   }

    catch (Throwable ex) {

     throw new BeanCreationException(mbd.getResourceDescription(), beanName,

     "Resolution of declared constructors on bean Class [" +

     beanClass.getName() +

     "] from ClassLoader [" + beanClass. getClassLoader()

     + "] failed", ex);

   }

  }

  //排序给定的构造函数,public 构造函数优先参数数量降序、非 public 构造函数参数数量降序

  AutowireUtils.sortConstructors(candidates);

   int minTypeDiffWeight = Integer.MAX_VALUE;

   Set<Constructor> ambiguousConstructors = null;

   List<Exception> causes = null;

   for (int i = 0; i < candidates.length; i++) {

    Constructor<?> candidate = candidates[i];

    Class[] paramTypes = candidate.getParameterTypes();

    if (constructorToUse != null && argsToUse.length > paramTypes.length) {

    //如果已经找到选用的构造函数或者需要的参数个数小于当前的构造函数参数个数则

    终止,因为已经按照参数个数降序排列

    break;

   }

    if (paramTypes.length < minNrOfArgs) {

    //参数个数不相等

    continue;

   }

     ArgumentsHolder argsHolder;

     if (resolvedValues != null) {

     //有参数则根据值构造对应参数类型的参数

      try {

       String[] paramNames = null;

       if (constructorPropertiesAnnotationAvailable) {

       //注释上获取参数名称

        (candidate, paramTypes.length);

        paramNames = ConstructorPropertiesChecker. evaluateAnnotation

      }

       if (paramNames == null) {

       //获取参数名称探索器

       NameDiscoverer();

        ParameterNameDiscoverer pnd = this.beanFactory. getParameter

        if (pnd != null) {

        //获取指定构造函数的参数名称

         paramNames = pnd.getParameterNames(candidate);

       }

      }

      //根据名称和数据类型创建参数持有者

       argsHolder = createArgumentArray(

       beanName, mbd, resolvedValues, bw, paramTypes, paramNames,

       candidate, autowiring);

     }

      catch (UnsatisfiedDependencyException ex) {

       if (this.beanFactory.logger.isTraceEnabled()) {

       this.beanFactory.logger.trace(

        "Ignoring constructor [" + candidate + "] of

        bean '" + beanName + "': " + ex);

      }

       if (i == candidates.length - 1 && constructorToUse == null) {

        if (causes != null) {

         for (Exception cause : causes) {

         this.beanFactory.onSuppressedException(cause);

        }

       }

        throw ex;

      }

       else {

        // Swallow and try next constructor.

        if (causes == null) {

         causes = new LinkedList<Exception>();

       }

       causes.add(ex);

       continue;

      }

     }

     }else {

      if (paramTypes.length != explicitArgs.length) {

      continue;

     }

     //构造函数没有参数的情况

     argsHolder = new ArgumentsHolder(explicitArgs);

   }

   //探测是否有不确定性的构造函数存在,例如不同构造函数的参数为父子关系

    int typeDiffWeight = (mbd.isLenientConstructorResolution() ?

     argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.

    getAssignabilityWeight(paramTypes));

   //如果它代表着当前最接近的匹配则选择作为构造函数

    if (typeDiffWeight < minTypeDiffWeight) {

     constructorToUse = candidate;

     argsHolderToUse = argsHolder;

     argsToUse = argsHolder.arguments;

     minTypeDiffWeight = typeDiffWeight;

     ambiguousConstructors = null;

    }else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {

     if (ambiguousConstructors == null) {

      ambiguousConstructors = new LinkedHashSet<Constructor>();

     ambiguousConstructors.add(constructorToUse);

    }

    ambiguousConstructors.add(candidate);

   }

  }

   if (constructorToUse == null) {

    throw new BeanCreationException(mbd.getResourceDescription(), beanName,

    "Could not resolve matching constructor " +

    "(hint: specify index/type/name arguments for simple

    parameters to avoid type ambiguities)");

   }else if (ambiguousConstructors != null && !mbd.isLenientConstructor

   Resolution()) {

    throw new BeanCreationException(mbd.getResourceDescription(), beanName,

    "Ambiguous constructor matches found in bean '" + beanName + "' " +

    "(hint: specify index/type/name arguments for simple

    parameters to avoid type ambiguities): " +

   ambiguousConstructors);

  }

   if (explicitArgs == null) {

   //将解析的构造函数加入缓存

    argsHolderToUse.storeCache(mbd, constructorToUse);

  }

 }

  try {

   Object beanInstance;

   if (System.getSecurityManager() != null) {

    final Constructor ctorToUse = constructorToUse;

    final Object[] argumentsToUse = argsToUse;

    beanInstance = AccessController.doPrivileged(new PrivilegedAction<

    Object>() {

     public Object run() {

      return beanFactory.getInstantiationStrategy().instantiate(

      mbd, beanName, beanFactory, ctorToUse, argumentsToUse);

    }

    }, beanFactory.getAccessControlContext());

  }

   else {

    beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(

    mbd, beanName, this.beanFactory, constructorToUse, argsToUse);

  }

  //将构建的实例加入 BeanWrapper 中

  bw.setWrappedInstance(beanInstance);

   return bw;

 }

  catch (Throwable ex) {

   throw new BeanCreationException(mbd.getResourceDescription(), beanName,

   "Instantiation of bean failed", ex);

 }

}

逻辑很复杂,函数代码量很大,不知道你是否坚持读完了整个函数并理解了整个功能呢?这里要先吐个槽,笔者觉得这个函数的写法完全不符合 Spring 的一贯风格,如果你一直跟随笔者的分析思路到这里,相信你或多或少对 Spring 的编码风格有所了解,Spring 的一贯做法是将复杂的逻辑分解,分成 N 个小函数的嵌套,每一层都是对下一层逻辑的总结及概要,这样使得每一层的逻辑会变得简单容易理解。在上面的函数中,包含着很多的逻辑实现,笔者觉得至少应该将逻辑封装在不同函数中而使得在 autowireConstructor 中的逻辑清晰明了。

我们总览一下整个函数,其实现的功能考虑了以下几个方面。

(1)构造函数参数的确定。

根据 explicitArgs 参数判断。

如果传入的参数 explicitArgs 不为空,那边可以直接确定参数,因为 explicitArgs 参数是在调用 Bean 的时候用户指定的,在 BeanFactory 类中存在这样的方法:

Object getBean(String name, Object... args) throws BeansException;

在获取 bean 的时候,用户不但可以指定 bean 的名称还可以指定 bean 所对应类的构造函数或者工厂方法的方法参数,主要用于静态工厂方法的调用,而这里是需要给定完全匹配的参数的,所以,便可以判断,如果传入参数 explicitArgs 不为空,则可以确定构造函数参数就是它。

缓存中获取。

除此之外,确定参数的办法如果之前已经分析过,也就是说构造函数参数已经记录在缓存中,那么便可以直接拿来使用。而且,这里要提到的是,在缓存中缓存的可能是参数的最终类型也可能是参数的初始类型,例如:构造函数参数要求的是 int 类型,但是原始的参数值可能是 String 类型的“1”,那么即使在缓存中得到了参数,也需要经过类型转换器的过滤以确保参数类型与对应的构造函数参数类型完全对应。

配置文件获取。

如果不能根据传入的参数 explicitArgs 确定构造函数的参数也无法在缓存中得到相关信息,那么只能开始新一轮的分析了。

分析从获取配置文件中配置的构造函数信息开始,经过之前的分析,我们知道,Spring 中配置文件中的信息经过转换都会通过 BeanDefinition 实例承载,也就是参数 mbd 中包含,那么可以通过调用 mbd.getConstructorArgumentValues() 来获取配置的构造函数信息。有了配置中的信息便可以获取对应的参数值信息了,获取参数值的信息包括直接指定值,如:直接指定构造函数中某个值为原始类型 String 类型,或者是一个对其他 bean 的引用,而这一处理委托给 resolveConstructorArguments 方法,并返回能解析到的参数的个数。

(2)构造函数的确定。

经过了第一步后已经确定了构造函数的参数,接下来的任务就是根据构造函数参数在所有构造函数中锁定对应的构造函数,而匹配的方法就是根据参数个数匹配,所以在匹配之前需要先对构造函数按照 public 构造函数优先参数数量降序、非 public 构造函数参数数量降序。这样可以在遍历的情况下迅速判断排在后面的构造函数参数个数是否符合条件。

由于在配置文件中并不是唯一限制使用参数位置索引的方式去创建,同样还支持指定参数名称进行设定参数值的情况,如<constructor-arg name="aa">,那么这种情况就需要首先确定构造函数中的参数名称。

获取参数名称可以有两种方式,一种是通过注解的方式直接获取,另一种就是使用 Spring 中提供的工具类 ParameterNameDiscoverer 来获取。构造函数、参数名称、参数类型、参数值都确定后就可以锁定构造函数以及转换对应的参数类型了。

(3)根据确定的构造函数转换对应的参数类型。

主要是使用 Spring 中提供的类型转换器或者用户提供的自定义类型转换器进行转换。

(4)构造函数不确定性的验证。

当然,有时候即使构造函数、参数名称、参数类型、参数值都确定后也不一定会直接锁定构造函数,不同构造函数的参数为父子关系,所以 Spring 在最后又做了一次验证。

(5)根据实例化策略以及得到的构造函数及构造函数参数实例化 Bean。后面章节中将进行讲解。

2.instantiateBean

经历了带有参数的构造函数的实例构造,相信你会非常轻松愉快地理解不带参数的构造函数的实例化过程。

protected BeanWrapper instantiateBean(final String beanName, final RootBean

Definition mbd) {

  try {

   Object beanInstance;

   final BeanFactory parent = this;

   if (System.getSecurityManager() != null) {

    beanInstance = AccessController.doPrivileged(new PrivilegedAction

    <Object>() {

     public Object run() {

      return getInstantiationStrategy().instantiate(mbd, beanName,

     parent);

    }

    }, getAccessControlContext());

  }

   else {

    beanInstance = getInstantiationStrategy().instantiate(mbd, beanName,

   parent);

  }

   BeanWrapper bw = new BeanWrapperImpl(beanInstance);

  initBeanWrapper(bw);

   return bw;

 }

  catch (Throwable ex) {

   throw new BeanCreationException(mbd.getResourceDescription(), beanName,

   "Instantiation of bean failed", ex);

 }

}

你会发现,此方法并没有什么实质性的逻辑,带有参数的实例构造中,Spring 把精力都放在了构造函数以及参数的匹配上,所以如果没有参数的话那将是非常简单的一件事,直接调用实例化策略进行实例化就可以了。

3.实例化策略

实例化过程中反复提到过实例化策略,那这又是做什么用的呢?其实,经过前面的分析,我们已经得到了足以实例化的所有相关信息,完全可以使用最简单的反射方法直接反射来构造实例对象,但是 Spring 却并没有这么做。

SimpleInstantiationStrategy.java

public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory

owner) {

 //如果有需要覆盖或者动态替换的方法则当然需要使用 cglib 进行动态代理,因为可以在创建代理的同

 时将动态方法织入类中,

 //但是如果没有需要动态改变得方法,为了方便直接反射就可以了

  if (beanDefinition.getMethodOverrides().isEmpty()) {

   Constructor<?> constructorToUse;

   synchronized (beanDefinition.constructorArgumentLock) {

    constructorToUse = (Constructor<?>)beanDefinition.resolvedConstructor

   OrFactoryMethod;

    if (constructorToUse == null) {

     final Class clazz = beanDefinition.getBeanClass();

     if (clazz.isInterface()) {

      throw new BeanInstantiationException(clazz, "Specified class

      is an interface");

    }

     try {

      if (System.getSecurityManager() != null) {

       constructorToUse = AccessController.doPrivileged(new

       PrivilegedExceptionAction<Constructor>() {

        public Constructor run() throws Exception {

         return clazz.getDeclaredConstructor((Class[]) null);

       }

      });

     }

      else {

      null);

       constructorToUse = clazz.getDeclaredConstructor((Class[])

     }

     constructorToUse;

      beanDefinition.resolvedConstructorOrFactoryMethod =

    }

     catch (Exception ex) {

      constructor found", ex);

      throw new BeanInstantiationException(clazz, "No default

    }

   }

  }

   return BeanUtils.instantiateClass(constructorToUse);

  }else {

   // Must generate CGLIB subclass.

   return instantiateWithMethodInjection(beanDefinition, beanName, owner);

 }

}

CglibSubclassingInstantiationStrategy.java

public Object instantiate(Constructor ctor, Object[] args) {

  Enhancer enhancer = new Enhancer();

 enhancer.setSuperclass(this.beanDefinition.getBeanClass());

  enhancer.setCallbackFilter(new CallbackFilterImpl());

  enhancer.setCallbacks(new Callback[] {

  NoOp.INSTANCE,

   new LookupOverrideMethodInterceptor(),

   new ReplaceOverrideMethodInterceptor()

 });

  return (ctor == null) ?

   enhancer.create() :

   enhancer.create(ctor.getParameterTypes(), args);

 }

看了上面两个函数后似乎我们已经感受到了 Spring 的良苦用心以及为了能更方便地使用 Spring 而做了大量的工作。程序中,首先判断如果 beanDefinition.getMethodOverrides() 为空也就是用户没有使用 replace 或者 lookup 的配置方法,那么直接使用反射的方式,简单快捷,但是如果使用了这两个特性,在直接使用反射的方式创建实例就不妥了,因为需要将这两个配置提供的功能切入进去,所以就必须要使用动态代理的方式将包含两个特性所对应的逻辑的拦截增强器设置进去,这样才可以保证在调用方法的时候会被相应的拦截器增强,返回值为包含拦截器的代理实例。

对于拦截器的处理方法非常简单,不再详细介绍,如果读者有兴趣,可以仔细研读第 7 章中关于 AOP 的介绍,对动态代理方面的知识会有更详细地介绍。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。