Spring Bean的实例化

Posted SanPiBrother

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Bean的实例化相关的知识,希望对你有一定的参考价值。

Bean的实例化

构造器的选择

构造器首先的是带有@AutoWire注解的有参构造器,没有的化就选择无参构造器

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
   // Make sure bean class is actually resolved at this point.
 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());
 }
   Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
 if (instanceSupplier != null) {
      return obtainFromSupplier(instanceSupplier, beanName);
 }
 // 工厂方法不为空,就使用工厂方法(xml中配置的factory-method)实例化
 if (mbd.getFactoryMethodName() != null) {
      return instantiateUsingFactoryMethod(beanName, mbd, args);
 }
   // Shortcut when re-creating the same bean...
  // 这里resolved 和 mbd.constructorArgumentsResolved 将会在 bean 第二次实例化后修改状态
 boolean resolved = false;
 boolean autowireNecessary = false;
 if (args == null) {
      synchronized (mbd.constructorArgumentLock) {
         // 第二次实例化同一个Bean时,会进入该分支
         if (mbd.resolvedConstructorOrFactoryMethod != null) {
            resolved = true;
 autowireNecessary = mbd.constructorArgumentsResolved;
 }
      }
   }
   if (resolved) {
      if (autowireNecessary) {
         return autowireConstructor(beanName, mbd, null, null);
 }
      else {
         // 通过无参构造器实例化对象
         return instantiateBean(beanName, mbd);
 }
   }
   // 寻找当前正在实例化的bean中有@Autowired注解的构造函数
 Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
 if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
         mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
      return autowireConstructor(beanName, mbd, ctors, args);
 }
   // Preferred constructors for default construction?
 ctors = mbd.getPreferredConstructors();
 if (ctors != null) {
      return autowireConstructor(beanName, mbd, ctors, null);
 }
   // 使用无参构造器进行实例化
 return instantiateBean(beanName, mbd);
}
从上面代码,我们发现一个注释叫shortcut,用于在重复创建相同的Bean对象时,提高效率。创建对象前,需要在众多构造器中,推断出合适的构造器,一旦完成实例化后,就将推断出的构造器constructorToUse存入BeanDefine中,以备下次实例化该Bean时使用,舍去再次推断构造器的步骤。
SimpleInstantiationStrategy的instantiate()方法中就是这样做的。
bd.resolvedConstructorOrFactoryMethod = constructorToUse;

SimpleInstantiationStrategy

Bean实例化有两种策略,一种是CGLIB,另一种是通过BeanUtil,即用JVM反射生成对象。
如果Bean中有@LookUp注解,或者xml中指定了lookup-method,那么就会采用CGLIB来实例化对象,因为需要重写@LookUp标记的方法,这种情况下很容易想到使用代理,使用代理,被代理类又不需实现接口,无疑CGLB方式合适。
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
   // Don\'t override the class with CGLIB if no overrides.
 if (!bd.hasMethodOverrides()) {
      Constructor<?> constructorToUse;
 synchronized (bd.constructorArgumentLock) {
         constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
 if (constructorToUse == null) {
            final Class<?> clazz = bd.getBeanClass();
 if (clazz.isInterface()) {
               throw new BeanInstantiationException(clazz, "Specified class is an interface");
 }
           //获取无参构造器去实例化Bean
            try {
               if (System.getSecurityManager() != null) {
                  constructorToUse = AccessController.doPrivileged(
                        (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
 }
               else {
                  constructorToUse = clazz.getDeclaredConstructor();
 }             
                // 用于前面提到的shortcurt,即后面重复实例化该Bean时,直接用该构造器
               bd.resolvedConstructorOrFactoryMethod = constructorToUse;
 }
            catch (Throwable ex) {
               throw new BeanInstantiationException(clazz, "No default constructor found", ex);
 }
         }
      }
      // 通过JVM反射功能生成实例化对象
      return BeanUtils.instantiateClass(constructorToUse);
 }
   else {
      // 通过CGLIB来生成实例化对象
 return instantiateWithMethodInjection(bd, beanName, owner);
 }
}

以上是关于Spring Bean的实例化的主要内容,如果未能解决你的问题,请参考以下文章

Spring 实例化bean的三种方式

Spring源码分析非懒加载的Bean实例化过程(下篇)

当没有代码的时候,Spring之Bean实例化过程是什么样子的呢?

Spring bean管理器 bean实例化的三种方式

spring-bean实例化三种方式

无法实例化Spring bean存储库