Spring IOC 容器源码简单分析(四)——真实创建Bean

前言

上篇只是在描创建单例的过程,小打小闹,真本事还得看我们createBeanInstance,走起了。

<6-2-1>解析createBeanInstance

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    
    Class<?> beanClass = resolveBeanClass(mbd, beanName);
    // 检测类是否为空 && 是否是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());
    }
    // 获取用于创建bean实例的回调,看方法的意思应该是这样,但是不太懂啥意思,希望 知道的能告知一下。
    // 看上去主要还是在getMergedBeanDefinition中的,overrideFrom设置的
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beanName);
    }
    
   
   // 如果工厂方法不为空,使用通过工厂方法构建 bean 对象。
    if (mbd.getFactoryMethodName() != null) {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    // 一个简短的重新创建bean,不用再重新判断用哪种方法构造实例。
    // 构建prototype 类型的 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) {
            // <6-2-1-1> 
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
            // <6-2-1-2>
            return instantiateBean(beanName, mbd);
        }
    }

    // 由后置处理器决定返回哪些构造方法。
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    // 下面的条件符合一个就通过构造方法来创建bean。
    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
        mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // 如果有默认首选的构造函数,那么确定一下。
    ctors = mbd.getPreferredConstructors();
    if (ctors != null) {
        return autowireConstructor(beanName, mbd, ctors, null);
    }

    // 没有什么特别的处理的话,就用无参构造函数。
    return instantiateBean(beanName, mbd);
}

Spring有三种构造bean对象的方式:

  1. 使用工厂方法方式
  2. 使用构造方法自动注入方式
  3. 使用默认构造方法方式。

上面的流程也描述一下:

  1. 检测类权限问题,不能,就抛出异常。
  2. 获取用于创建bean实例的回调,有就走另一块逻辑。
  3. 判断是否有工厂方法,有就走工厂方法构造,然后返回。
  4. 再判断之前是否之前解析过,看看能不能走捷径。
  5. 没有的话,就看条件选是使用构造方法注入还是默认的。

老实说,我都觉得麻烦,都到6-2-1-1这种了,绕死我了。但还得老老实实看。工厂方法我简单看了下,太长了,而且其实和构造方法自动注入差不多,我就不写了,有兴趣的可以自己去看下。

<6-2-1-1>构造方法自动注入创建实例-autowireConstructor

protected BeanWrapper autowireConstructor(
			String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {

    return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}

public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
			@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
    // 新建一下BeanWrapperImpl并初始化一下
    BeanWrapperImpl bw = new BeanWrapperImpl();
    this.beanFactory.initBeanWrapper(bw);

    Constructor<?> constructorToUse = null;
    ArgumentsHolder argsHolderToUse = null;
    Object[] argsToUse = null;
    
    if (explicitArgs != null) {
        argsToUse = explicitArgs;
    }
    else {
        // 参数为空的情况。
        Object[] argsToResolve = null;
        synchronized (mbd.constructorArgumentLock) {
            // 获取解析的构造方法或工厂方法
            constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
            // 如果不为空 && 构造函数参数已解决(该值会在下面设为true,也就是说第一次进来的时候是不成立的)
            if (constructorToUse != null && mbd.constructorArgumentsResolved) {
                // 找到缓存的构造参数。
                argsToUse = mbd.resolvedConstructorArguments;
                if (argsToUse == null) {
                    // 获取准备好了的构造方法参数
                    argsToResolve = mbd.preparedConstructorArguments;
                }
            }
        }
        // 如果构造方法参数不为空
        if (argsToResolve != null) {
            // 那么就去解析。
            argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
        }
    }

    if (constructorToUse == null || argsToUse == null) {
        // 采用指定的构造函数
        Constructor<?>[] candidates = chosenCtors;
        if (candidates == null) {
            // 获取bean的class
            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);
            }
        }
        // 如果构造方法只有一个 && 参数为空 && bean有无参的构造方法。
        // 那么设置一系列值,再返回
        if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
            Constructor<?> uniqueCandidate = candidates[0];
            if (uniqueCandidate.getParameterCount() == 0) {
                synchronized (mbd.constructorArgumentLock) {
                    
                    mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
                    mbd.constructorArgumentsResolved = true;
                    mbd.resolvedConstructorArguments = EMPTY_ARGS;
                }
                bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
                return bw;
            }
        }

        // 获取自动装配的值。
        boolean autowiring = (chosenCtors != null ||
                              mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
        ConstructorArgumentValues resolvedValues = null;

        int minNrOfArgs;
        if (explicitArgs != null) {
            minNrOfArgs = explicitArgs.length;
        }
        else {
            ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
            resolvedValues = new ConstructorArgumentValues();
            // 确定构造方法参数数量,同时将参数数据缓存到resolvedValues,该resolvedValues是一个构造函数参数 的值 的持有者。
            minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
        }
        
        // 给构造方法排序,按访问权限级别(公开->非公开)然后参数数量(数量由多->少)来排。
        AutowireUtils.sortConstructors(candidates);
        int minTypeDiffWeight = Integer.MAX_VALUE;
        Set<Constructor<?>> ambiguousConstructors = null;
        LinkedList<UnsatisfiedDependencyException> causes = null;
        // 遍历排好序的构造方法
        for (Constructor<?> candidate : candidates) {
            // 获取参数数量。
            int parameterCount = candidate.getParameterCount();
            // 由于构造方法已经按参数数量进行了多到少的排序,因此如果能用的参数数量大于该构造方法的参数数量,要么是找到了适合的构造函数,要么是没有匹配的。
            // 这样就可以直接结束了。
            if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) {
                break;
            }
            // 如果该构造方法的参数数量 < 能用的参数数量,跳过这个。
            if (parameterCount < minNrOfArgs) {
                continue;
            }

            ArgumentsHolder argsHolder;
            Class<?>[] paramTypes = candidate.getParameterTypes();
            
            if (resolvedValues != null) {
                try {
                    // 判断该构造方法是否有 ConstructorProperties 注解,若有,则取注解中的值。
                    String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
                    if (paramNames == null) {
                        ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                        if (pnd != null) {
                            // 拿到参数名。
                            paramNames = pnd.getParameterNames(candidate);
                        }
                    }
                    // 进行类型转换,由于在Spring中都是String类型的,需要转化为参数实际需要的类型。
                    argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
                                                     getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
                }
                catch (UnsatisfiedDependencyException ex) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
                    }
                    // Swallow and try next constructor.
                    if (causes == null) {
                        causes = new LinkedList<>();
                    }
                    causes.add(ex);
                    continue;
                }
            }
            else {
                // 给定的显式参数和参数长度必须完全匹配。
                if (parameterCount != explicitArgs.length) {
                    continue;
                }
                argsHolder = new ArgumentsHolder(explicitArgs);
            }
            // 根据以宽松模式还是严格模式解析构造函数,选取不同的方案,计算这个差异权重。
            // 不好意思,这块没太看懂,希望知道的能告知一番。
            int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                                  argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
            // Choose this constructor if it represents the closest match.
            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<>();
                    ambiguousConstructors.add(constructorToUse);
                }
                ambiguousConstructors.add(candidate);
            }
        }
        // 如果上面未能筛选出合适的构造方法,这里将抛出 BeanCreationException 异常
        if (constructorToUse == null) {
            if (causes != null) {
                UnsatisfiedDependencyException ex = causes.removeLast();
                for (Exception cause : causes) {
                    this.beanFactory.onSuppressedException(cause);
                }
                throw ex;
            }
            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.isLenientConstructorResolution()) {
            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);
        }
         
        // 缓存相关信息,
        //   1. 已解析出的构造方法对象 resolvedConstructorOrFactoryMethod
        //   2. 构造方法参数列表是否已解析标志 constructorArgumentsResolved
        //   3. 参数值列表 resolvedConstructorArguments 或 preparedConstructorArguments
        if (explicitArgs == null && argsHolderToUse != null) {
            argsHolderToUse.storeCache(mbd, constructorToUse);
        }
    }

    Assert.state(argsToUse != null, "Unresolved constructor arguments");
    // 调用实例化策略创建实例,默认情况下使用反射创建实例。如果 bean 的配置信息中
    // 包含 lookup-method 和 replace-method,则通过 CGLIB 增强 bean 实例
    // 再设置 beanInstance 到 BeanWrapperImpl 对象中
    bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
    return bw;
}

这个方法有逻辑还是蛮复杂的,总结一下。

  1. 新建一个BeanWrapperImpl并初始化一下。
  2. 解析构造方法的参数列表。
  3. 给构造方法排序,按访问权限级别(公开->非公开)然后参数数量(数量由多->少)来排。
  4. 选取合适的构造方法。
  5. 缓存已筛选出的构造方法以及参数值列表,方便下次快捷建立。
  6. 使用实例化策略创建 bean 对象
  7. 将 bean 对象放入 BeanWrapperImpl 对象中,并返回该对象。

大致是这么个流程,具体细节可以看文章。

<6-2-1-2>使用默认的构造方法实例bean-instantiateBean

protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
   try {
      Object beanInstance;
      // 这个是安全相关的,不关心了。
      if (System.getSecurityManager() != null) {
         beanInstance = AccessController.doPrivileged(
               (PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this),
               getAccessControlContext());
      }
      else {
         // 调用实例化策略创建实例,默认情况下使用反射创建对象。如果 bean 的配置信息中
         // 包含 lookup-method 和 replace-method,则通过 CGLIB 创建 bean 对象
         // 这个和上面的最后一步是一样的,
         beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
      }
      BeanWrapper bw = new BeanWrapperImpl(beanInstance);
      initBeanWrapper(bw);
      return bw;
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
   }
}

默认方法来实例化bean比上面那个简单许多,不多解释了,下面看看两个都能用到的instantiate。

实例化策略创建实例-instantiate

public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
   // 判断bean 配置中是否配置了 lookup-method 或 replace-method,没有就进。
   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");
            }
            try {
               if (System.getSecurityManager() != null) {
                  constructorToUse = AccessController.doPrivileged(
                        (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
               }
               else {
                  // 获取默认构造方法
                  constructorToUse = clazz.getDeclaredConstructor();
               }
               // 设置 resolvedConstructorOrFactoryMethod
               bd.resolvedConstructorOrFactoryMethod = constructorToUse;
            }
            catch (Throwable ex) {
               throw new BeanInstantiationException(clazz, "No default constructor found", ex);
            }
         }
      }
      // 再调用这个。
      return BeanUtils.instantiateClass(constructorToUse);
   }
   else {
      // 有就需要CGlib来搞。
      return instantiateWithMethodInjection(bd, beanName, owner);
   }
}

CGlib的就不看了。再看一下instantiateClass

public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
   Assert.notNull(ctor, "Constructor must not be null");
   try {
      // 设置为构造方法可访问,
      ReflectionUtils.makeAccessible(ctor);
      if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
         return KotlinDelegate.instantiateClass(ctor, args);
      }
      else {
         // 获取参数类型,做判断啥的。
         Class<?>[] parameterTypes = ctor.getParameterTypes();
         Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
         Object[] argsWithDefaultValues = new Object[args.length];
         for (int i = 0 ; i < args.length; i++) {
            if (args[i] == null) {
               Class<?> parameterType = parameterTypes[i];
               argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
            }
            else {
               argsWithDefaultValues[i] = args[i];
            }
         }
         // 最后就反射创建bean实例。
         return ctor.newInstance(argsWithDefaultValues);
      }
   }
   // 一堆catch
}

至此,终于把bean给真实的创建出来了!写了四篇,终于到了,累了都。

最后的话

写在最后,其实后面还有属性填充和一些其他的动作,有兴趣的可以自己去看下,我感觉我写到这差不多了,都快看麻了,主要是也没人看,只能说我是在写给自己看的吧哈哈哈哈哈。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值