spring深入学习(十九) IOC 之 Factory 实例化 bean

2023-11-12

这篇我们关注创建 bean 过程中的第一个步骤:实例化 bean,对应的方法为:createBeanInstance(),如下:

   protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
        // 解析 bean,将 bean 类名解析为 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());
        }

        // 如果存在 Supplier 回调,则使用给定的回调方法初始化策略
        Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
        if (instanceSupplier != null) {
            return obtainFromSupplier(instanceSupplier, beanName);
        }

        // 如果工厂方法不为空,则使用工厂方法初始化策略
        if (mbd.getFactoryMethodName() != null)  {
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }

        boolean resolved = false;
        boolean autowireNecessary = false;
        if (args == null) {
            // constructorArgumentLock 构造函数的常用锁
            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);
            }
        }

        // 确定解析的构造函数
        // 主要是检查已经注册的 SmartInstantiationAwareBeanPostProcessor
        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);
    }

实例化 bean 是一个复杂的过程,其主要的逻辑为:

  • 如果存在 Supplier 回调,则调用 obtainFromSupplier() 进行初始化
  • 如果存在工厂方法,则使用工厂方法进行初始化
  • 首先判断缓存,如果缓存中存在,即已经解析过了,则直接使用已经解析了的,根据 constructorArgumentsResolved 参数来判断是使用构造函数自动注入还是默认构造函数
  • 如果缓存中没有,则需要先确定到底使用哪个构造函数来完成解析工作,因为一个类有多个构造函数,每个构造函数都有不同的构造参数,所以需要根据参数来锁定构造函数并完成初始化,如果存在参数则使用相应的带有参数的构造函数,否则使用默认构造函数。

下面就上面四种情况做分别说明。

obtainFromSupplier()

Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
    return obtainFromSupplier(instanceSupplier, beanName);
}

首先从 BeanDefinition 中获取 Supplier,如果不为空,则调用 obtainFromSupplier() 。那么 Supplier 是什么呢?在这之前也没有提到过这个字段。

public interface Supplier<T> {
    T get();
}

Supplier 接口仅有一个功能性的 get(),该方法会返回一个 T 类型的对象,有点儿类似工厂方法。这个接口有什么作用?用于指定创建 bean 的回调,如果我们设置了这样的回调,那么其他的构造器或者工厂方法都会没有用。在什么设置该参数呢?Spring 提供了相应的 setter 方法,如下:

    public void setInstanceSupplier(@Nullable Supplier<?> instanceSupplier) {
        this.instanceSupplier = instanceSupplier;
    }

在构造 BeanDefinition 的时候设置了该值,如下(以 RootBeanDefinition 为例):

    public <T> RootBeanDefinition(@Nullable Class<T> beanClass, String scope, @Nullable Supplier<T> instanceSupplier) {
        super();
        setBeanClass(beanClass);
        setScope(scope);
        setInstanceSupplier(instanceSupplier);
    }

如果设置了 instanceSupplier 则调用 obtainFromSupplier() 完成 bean 的初始化,如下:

    protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {
        String outerBean = this.currentlyCreatedBean.get();
        this.currentlyCreatedBean.set(beanName);
        Object instance;
        try {
          // 调用 Supplier 的 get(),返回一个对象
            instance = instanceSupplier.get();
        }
        finally {
            if (outerBean != null) {
                this.currentlyCreatedBean.set(outerBean);
            }
            else {
                this.currentlyCreatedBean.remove();
            }
        }
        // 根据对象构造 BeanWrapper 对象
        BeanWrapper bw = new BeanWrapperImpl(instance);
        // 初始化 BeanWrapper
        initBeanWrapper(bw);
        return bw;
    }

代码很简单,调用 调用 Supplier 的 get() 方法,获得一个 bean 实例对象,然后根据该实例对象构造一个 BeanWrapper 对象 bw,最后初始化该对象。有关于 BeanWrapper 后面专门出文讲解。

instantiateUsingFactoryMethod()

如果存在工厂方法,则调用 instantiateUsingFactoryMethod() 完成 bean 的初始化工作(方法实现比较长,细节比较复杂,各位就硬着头皮看吧)。

    protected BeanWrapper instantiateUsingFactoryMethod(
            String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
        return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
    }

构造一个 ConstructorResolver 对象,然后调用其 instantiateUsingFactoryMethod() 方法。ConstructorResolver 是构造方法或者工厂类初始化 bean 的委托类。

      public BeanWrapper instantiateUsingFactoryMethod(
            final String beanName, final RootBeanDefinition mbd, @Nullable final Object[] explicitArgs) {

        // 构造 BeanWrapperImpl 对象
        BeanWrapperImpl bw = new BeanWrapperImpl();
        // 初始化 BeanWrapperImpl
        // 向BeanWrapper对象中添加 ConversionService 对象和属性编辑器 PropertyEditor 对象
        //
        this.beanFactory.initBeanWrapper(bw);

        Object factoryBean;
        Class<?> factoryClass;
        boolean isStatic;

        // 工厂名不为空
        String factoryBeanName = mbd.getFactoryBeanName();
        if (factoryBeanName != null) {
            if (factoryBeanName.equals(beanName)) {
                throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
                        "factory-bean reference points back to the same bean definition");
            }
            // 获取工厂实例
            factoryBean = this.beanFactory.getBean(factoryBeanName);
            if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
                throw new ImplicitlyAppearedSingletonException();
            }
            factoryClass = factoryBean.getClass();
            isStatic = false;
        }
        else {
            // 工厂名为空,则其可能是一个静态工厂

            // 静态工厂创建bean,必须要提供工厂的全类名
            if (!mbd.hasBeanClass()) {
                throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
                        "bean definition declares neither a bean class nor a factory-bean reference");
            }
            factoryBean = null;
            factoryClass = mbd.getBeanClass();
            isStatic = true;
        }

        // 工厂方法
        Method factoryMethodToUse = null;
        ConstructorResolver.ArgumentsHolder argsHolderToUse = null;
        // 参数
        Object[] argsToUse = null;

        // 工厂方法的参数
        // 如果指定了构造参数则直接使用
        // 在调用 getBean 方法的时候指定了方法参数
        if (explicitArgs != null) {
            argsToUse = explicitArgs;
        }
        else {
            // 没有指定,则尝试从配置文件中解析
            Object[] argsToResolve = null;
            // 首先尝试从缓存中获取
            synchronized (mbd.constructorArgumentLock) {
                // 获取缓存中的构造函数或者工厂方法
                factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
                if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
                    // 获取缓存中的构造参数
                    argsToUse = mbd.resolvedConstructorArguments;
                    if (argsToUse == null) {
                        // 获取缓存中的构造函数参数的包可见字段
                        argsToResolve = mbd.preparedConstructorArguments;
                    }
                }
            }
            // 缓存中存在,则解析存储在 BeanDefinition 中的参数
            // 如给定方法的构造函数 A(int ,int ),则通过此方法后就会把配置文件中的("1","1")转换为 (1,1)
            // 缓存中的值可能是原始值也有可能是最终值
            if (argsToResolve != null) {
                argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve);
            }
        }

        //
        if (factoryMethodToUse == null || argsToUse == null) {
            // 获取工厂方法的类全名称
            factoryClass = ClassUtils.getUserClass(factoryClass);

            // 获取所有待定方法
            Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
            // 检索所有方法,这里是对方法进行过滤
            List<Method> candidateSet = new ArrayList<>();
            for (Method candidate : rawCandidates) {
                // 如果有static 且为工厂方法,则添加到 candidateSet 中
                if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
                    candidateSet.add(candidate);
                }
            }

            Method[] candidates = candidateSet.toArray(new Method[0]);
            // 排序构造函数
            // public 构造函数优先参数数量降序,非public 构造函数参数数量降序
            AutowireUtils.sortFactoryMethods(candidates);

            // 用于承载解析后的构造函数参数的值
            ConstructorArgumentValues resolvedValues = null;
            boolean autowiring = (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
            int minTypeDiffWeight = Integer.MAX_VALUE;
            Set<Method> ambiguousFactoryMethods = null;

            int minNrOfArgs;
            if (explicitArgs != null) {
                minNrOfArgs = explicitArgs.length;
            }
            else {
                // getBean() 没有传递参数,则需要解析保存在 BeanDefinition 构造函数中指定的参数
                if (mbd.hasConstructorArgumentValues()) {
                    // 构造函数的参数
                    ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
                    resolvedValues = new ConstructorArgumentValues();
                    // 解析构造函数的参数
                    // 将该 bean 的构造函数参数解析为 resolvedValues 对象,其中会涉及到其他 bean
                    minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
                }
                else {
                    minNrOfArgs = 0;
                }
            }

            LinkedList<UnsatisfiedDependencyException> causes = null;

            for (Method candidate : candidates) {
                // 方法体的参数
                Class<?>[] paramTypes = candidate.getParameterTypes();

                if (paramTypes.length >= minNrOfArgs) {
                    // 保存参数的对象
                    ArgumentsHolder argsHolder;

                    // getBean()传递了参数
                    if (explicitArgs != null){
                        // 显示给定参数,参数长度必须完全匹配
                        if (paramTypes.length != explicitArgs.length) {
                            continue;
                        }
                        // 根据参数创建参数持有者
                        argsHolder = new ArgumentsHolder(explicitArgs);
                    }
                    else {
                        // 为提供参数,解析构造参数
                        try {
                            String[] paramNames = null;
                            // 获取 ParameterNameDiscoverer 对象
                            // ParameterNameDiscoverer 是用于解析方法和构造函数的参数名称的接口,为参数名称探测器
                            ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                            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 factory method [" + candidate +
                                        "] of bean '" + beanName + "': " + ex);
                            }
                            if (causes == null) {
                                causes = new LinkedList<>();
                            }
                            causes.add(ex);
                            continue;
                        }
                    }

                    // isLenientConstructorResolution 判断解析构造函数的时候是否以宽松模式还是严格模式
                    // 严格模式:解析构造函数时,必须所有的都需要匹配,否则抛出异常
                    // 宽松模式:使用具有"最接近的模式"进行匹配
                    // typeDiffWeight:类型差异权重
                    int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                            argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
                    // 代表最接近的类型匹配,则选择作为构造函数
                    if (typeDiffWeight < minTypeDiffWeight) {
                        factoryMethodToUse = candidate;
                        argsHolderToUse = argsHolder;
                        argsToUse = argsHolder.arguments;
                        minTypeDiffWeight = typeDiffWeight;
                        ambiguousFactoryMethods = null;
                    }

                    // 如果具有相同参数数量的方法具有相同的类型差异权重,则收集此类型选项
                    // 但是,仅在非宽松构造函数解析模式下执行该检查,并显式忽略重写方法(具有相同的参数签名)
                    else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
                            !mbd.isLenientConstructorResolution() &&
                            paramTypes.length == factoryMethodToUse.getParameterCount() &&
                            !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {

                        // 查找到多个可匹配的方法
                        if (ambiguousFactoryMethods == null) {
                            ambiguousFactoryMethods = new LinkedHashSet<>();
                            ambiguousFactoryMethods.add(factoryMethodToUse);
                        }
                        ambiguousFactoryMethods.add(candidate);
                    }
                }
            }

            // 没有可执行的工厂方法,抛出异常
            if (factoryMethodToUse == null) {
                if (causes != null) {
                    UnsatisfiedDependencyException ex = causes.removeLast();
                    for (Exception cause : causes) {
                        this.beanFactory.onSuppressedException(cause);
                    }
                    throw ex;
                }
                List<String> argTypes = new ArrayList<>(minNrOfArgs);
                if (explicitArgs != null) {
                    for (Object arg : explicitArgs) {
                        argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
                    }
                }
                else if (resolvedValues != null){
                    Set<ConstructorArgumentValues.ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());
                    valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
                    valueHolders.addAll(resolvedValues.getGenericArgumentValues());
                    for (ConstructorArgumentValues.ValueHolder value : valueHolders) {
                        String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
                                (value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
                        argTypes.add(argType);
                    }
                }
                String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "No matching factory method found: " +
                                (mbd.getFactoryBeanName() != null ?
                                        "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
                                "factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
                                "Check that a method with the specified name " +
                                (minNrOfArgs > 0 ? "and arguments " : "") +
                                "exists and that it is " +
                                (isStatic ? "static" : "non-static") + ".");
            }
            else if (void.class == factoryMethodToUse.getReturnType()) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Invalid factory method '" + mbd.getFactoryMethodName() +
                                "': needs to have a non-void return type!");
            }
            else if (ambiguousFactoryMethods != null) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Ambiguous factory method matches found in bean '" + beanName + "' " +
                                "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
                                ambiguousFactoryMethods);
            }

            if (explicitArgs == null && argsHolderToUse != null) {
                // 将解析的构造函数加入缓存
                argsHolderToUse.storeCache(mbd, factoryMethodToUse);
            }
        }

        try {
            // 实例化 bean
            Object beanInstance;

            if (System.getSecurityManager() != null) {
                final Object fb = factoryBean;
                final Method factoryMethod = factoryMethodToUse;
                final Object[] args = argsToUse;
                // 通过执行工厂方法来创建bean示例
                beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
                                beanFactory.getInstantiationStrategy().instantiate(mbd, beanName, beanFactory, fb, factoryMethod, args),
                        beanFactory.getAccessControlContext());
            }
            else {
                // 通过执行工厂方法来创建bean示例
                beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
                        mbd, beanName, this.beanFactory, factoryBean, factoryMethodToUse, argsToUse);
            }

            // 包装为 BeanWraper 对象
            bw.setBeanInstance(beanInstance);
            return bw;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Bean instantiation via factory method failed", ex);
        }
    }

instantiateUsingFactoryMethod() 方法体实在是太大了,处理细节感觉很复杂,LZ是硬着头皮看完的,中间断断续续的。吐槽这里的代码风格,完全不符合我们前面看的 Spring 代码风格。Spring 的一贯做法是将一个复杂逻辑进行拆分,分为多个细小的模块进行嵌套,每个模块负责一部分功能,模块与模块之间层层嵌套,上一层一般都是对下一层的总结和概括,这样就会使得每一层的逻辑变得清晰易懂。

回归到上面的方法体,虽然代码体量大,但是总体我们还是可看清楚这个方法要做的事情。一句话概括就是:确定工厂对象,然后获取构造函数和构造参数,最后调用 InstantiationStrategy 对象的 instantiate() 来创建 bean 实例。下面我们就这个句概括的话进行拆分并详细说明。

确定工厂对象

首先获取工厂方法名,若工厂方法名不为空,则调用 beanFactory.getBean() 获取工厂对象,若为空,则可能为一个静态工厂,对于静态工厂则必须提供工厂类的全类名,同时设置 factoryBean = null

构造参数确认

工厂对象确定后,则是确认构造参数。构造参数的确认主要分为三种情况:explicitArgs 参数、缓存中获取、配置文件中解析。

explicitArgs 参数

explicitArgs 参数是我们调用 getBean() 时传递景来,一般该参数,该参数就是用于初始化 bean 时所传递的参数,如果该参数不为空,则可以确定构造函数的参数就是它了。

缓存中获取

在该方法的最后,我们会发现这样一段代码:argsHolderToUse.storeCache(mbd, factoryMethodToUse) ,这段代码主要是将构造函数、构造参数保存到缓存中,如下:

        public void storeCache(RootBeanDefinition mbd, Executable constructorOrFactoryMethod) {
            synchronized (mbd.constructorArgumentLock) {
                mbd.resolvedConstructorOrFactoryMethod = constructorOrFactoryMethod;
                mbd.constructorArgumentsResolved = true;
                if (this.resolveNecessary) {
                    mbd.preparedConstructorArguments = this.preparedArguments;
                }
                else {
                    mbd.resolvedConstructorArguments = this.arguments;
                }
            }
        }

其中涉及到的几个参数 constructorArgumentLock、resolvedConstructorOrFactoryMethod、constructorArgumentsResolved、resolvedConstructorArguments。这些参数都是跟构造函数、构造函数缓存有关的。

  • constructorArgumentLock:构造函数的缓存锁
  • resolvedConstructorOrFactoryMethod:缓存已经解析的构造函数或者工厂方法
  • constructorArgumentsResolved:标记字段,标记构造函数、参数已经解析了。默认为false
  • resolvedConstructorArguments:缓存已经解析的构造函数参数,包可见字段

所以从缓存中获取就是提取这几个参数的值,如下:

            synchronized (mbd.constructorArgumentLock) {
                // 获取缓存中的构造函数或者工厂方法
                factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
                if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
                    // 获取缓存中的构造参数
                    argsToUse = mbd.resolvedConstructorArguments;
                    if (argsToUse == null) {
                        // 获取缓存中的构造函数参数的包可见字段
                        argsToResolve = mbd.preparedConstructorArguments;
                    }
                }
            }

如果缓存中存在构造参数,则需要调用 resolvePreparedArguments() 方法进行转换,因为缓存中的值有可能是最终值也有可能不是最终值,比如我们构造函数中的类型为 Integer 类型的 1 ,但是原始的参数类型有可能是 String 类型的 1 ,所以即便是从缓存中得到了构造参数也需要经过一番的类型转换确保参数类型完全对应。

配置文件中解析

即没有通过传递参数的方式传递构造参数,缓存中也没有,那就只能通过解析配置文件获取构造参数了。

在 bean 解析类的博文中我们了解了,配置文件中的信息都会转换到 BeanDefinition 实例对象中,所以配置文件中的参数可以直接通过 BeanDefinition 对象获取。代码如下:

if (mbd.hasConstructorArgumentValues()) {
    // 构造函数的参数
    ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
    resolvedValues = new ConstructorArgumentValues();
    // 解析构造函数的参数
    // 将该 bean 的构造函数参数解析为 resolvedValues 对象,其中会涉及到其他 bean
    minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}

通过 BeanDefinition 的 getConstructorArgumentValues() 就可以获取构造信息了,有了构造信息就可以获取相关的参数值信息了,获取的参数信息包括直接值和引用,这一步骤的处理交由 resolveConstructorArguments() 完成,该方法会将构造参数信息解析为 resolvedValues 对象 并返回解析到的参数个数。

构造函数

确定构造参数后,下一步则是确定构造函数。第一步则是通过 getCandidateMethods() 获取所有的构造方法,同时对构造方法进行刷选,然后在对其进行排序处理(AutowireUtils.sortFactoryMethods(candidates)),排序的主要目的是为了能够更加方便的找到匹配的构造函数,因为构造函数的确认是根据参数个数确认的。排序的规则是:public 构造函数优先参数数量降序、非 public 构造参数数量降序。

通过迭代 candidates(包含了所有要匹配的构造函数)的方式,一次比较其参数,如果显示提供了参数(explicitArgs != null),则直接比较两者是否相等,如果相等则表示找到了,否则继续比较。如果没有显示提供参数,则需要获取 ParameterNameDiscoverer 对象,该对象为参数名称探测器,主要用于发现方法和构造函数的参数名称。

将参数包装成 ArgumentsHolder 对象,该对象用于保存参数,我们称之为参数持有者。当将对象包装成 ArgumentsHolder 对象后,我们就可以通过它来进行构造函数匹配,匹配分为严格模式和宽松模式。

  • 严格模式:解析构造函数时,必须所有参数都需要匹配,否则抛出异常
  • 宽松模式:使用具有”最接近的模式”进行匹配

判断的依据是根据 BeanDefinition 的 isLenientConstructorResolution 属性(该参数是我们在构造 AbstractBeanDefinition 对象是传递的)来获取类型差异权重(typeDiffWeight) 的。如果 typeDiffWeight < minTypeDiffWeight ,则代表“最接近的模式”,选择其作为构造函数,否则只有两者具有相同的参数数量且类型差异权重相等才会纳入考虑范围。

至此,构造函数已经确认了。

创建 bean 实例

工厂对象、构造函数、构造参数都已经确认了,则最后一步就是调用 InstantiationStrategy 对象的 instantiate() 来创建 bean 实例,如下:

public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
            @Nullable Object factoryBean, final Method factoryMethod, @Nullable Object... args) {

        try {
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    ReflectionUtils.makeAccessible(factoryMethod);
                    return null;
                });
            }
            else {
                ReflectionUtils.makeAccessible(factoryMethod);
            }

            Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
            try {
                currentlyInvokedFactoryMethod.set(factoryMethod);
                // 执行工厂方法,并返回实例
                Object result = factoryMethod.invoke(factoryBean, args);
                if (result == null) {
                    result = new NullBean();
                }
                return result;
            }
            finally {
                if (priorInvokedFactoryMethod != null) {
                    currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
                }
                else {
                    currentlyInvokedFactoryMethod.remove();
                }
            }
        }
        // 省略一波 catch
    }

instantiate() 最核心的部分就是利用 Java 反射执行工厂方法并返回创建好的实例,也就是这段代码:

Object result = factoryMethod.invoke(factoryBean, args);

到这里 instantiateUsingFactoryMethod() 已经分析完毕了。

createBeanInstance() 还有两个重要方法 autowireConstructor() 和 instantiateBean() ,由于篇幅问题,所以将这两个方法放在下篇博客分析。敬请期待!!!

内容是楼主转载,仅用于个人学习,帮助个人成长所用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

spring深入学习(十九) IOC 之 Factory 实例化 bean 的相关文章

  • Linux 查看服务器内存、CPU 命令

    1 服务器CPU情况 cat 1 查看物理CPU个数 Procs 进程 cat proc cpuinfo grep physical id sort uniq wc l 2 查看服务器CPU内核个数 cat proc cpuinfo gre
  • 关于若依框架中v-hasRole/v-hasPermi作用到el-table-column中无法生效问题

    在某些情况下 它是不适合使用v hasPermi 如元素标签组件 只能通过手动设置v if 可以使用全局权限判断函数 用法和指令 v hasPermi 类似
  • 静态链表基本操作

    增 删 查找位序下标 查找空元素操作 next 1为表最后一个元素 next 2为空元素 define CRT SECURE NO WARNINGS include
  • 如何选择合适的 API 网关

    如今 API 网关是设计具有多个 API 服务或微服务的分布式系统架构的重要组成部分 这篇文章帮助您了解什么是 API 网关 何时以及为何使用它 并指导您如何为您的应用程序选择最佳的 API 网关解决方案 什么是 API 网关 API 网关
  • 06-Java框架-SpringBoot

    一 SpringBoot介绍 之前为了搭建一个SSM的项目 需要导入各种jar包和添加各种xml的配置 相对来时是较为复杂的 SpringBoot倡导的是几乎0配置搭建Spring应用 官网 https spring io projects
  • 卷麻了,新来的00后实在是太卷了...

    在程序员职场上 什么样的人最让人反感呢 是技术不好的人吗 并不是 技术不好的同事 我们可以帮他 是技术太强的人吗 也不是 技术很强的同事 可遇不可求 向他学习还来不及呢 真正让人反感的 是技术平平 却急于表现自己的人 每天加班到12点 在老
  • 数据结构知识点总结

    一 顺序表和链表 1 顺序表 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构 一般情况下采用数组存储 在数组 上完成数据的增删查改 静态顺序表 使用定长数组存储 动态顺序表 使用动态开辟的数组存储 常用 2 链表 链表是一种
  • node settings must not contain any index level settings

    本人安装的ES是7 6 1版本 报错意思为 节点设置不能包含任何索引级别设置 也就是说报错是因为 在elasticsearce yml文件中对索引进行了配置 应该是新版本不支持这样配置 删除相应的索引配置即可 index refresh i
  • 浏览器H5获取地理位置api——navigator.geolocation

    地理位置 API Geolocation API 允许用户向 web 应用程序提供他们的位置 出于隐私考虑 报告地理位置前会先请求用户许可 PS 出于安全考虑 当网页请求获取用户位置信息时 用户会被提示进行授权 注意不同浏览器在请求权限时有
  • Docker报错(Error): Layer already exists如何处理

    作者 变优秀的小白 Github 关注YX XiaoBai 爱好 Americano More Ice QQ学习交流群 new 811792998 Error Layer already exists 当你修改了源码 准备docker pu
  • 从程序员的角度设计一个Java的神经网络

    欢迎大家前往云 社区 获取更多海量技术实践干货哦 来自维基百科 人工神经网络 ANN 或连接系统是受生物神经网络启发构成生物大脑的计算系统 这样的系统通过考虑例子来学习 逐步提高性能 来完成任务 通常没有任务特定的编程 用Java或任何其他
  • 什么是GameFi?如何理解这一概念?

    GameFi的爆火是区块链在项目创新和概念创新方面具有先天优势的体现 时至今日 GameFi已经成为继DeFi之后的又一大行业热词 那么该怎么理解GameFi概念 GameFi又具有什么优势呢 01 GameFi是什么 如果说DeFi是把现
  • JVM笔记 -- JVM的发展以及基于栈的指令集架构

    2011年 JDK7发布 1 7u4中 开始启用新的垃圾回收器G1 但是不是默认 2017年 发布JDK9 G1成为默认GC 代替CMS 一般公司使用jdk8的时候 会通过参数 指定GC为G1 2018年 发布JDK11 带来了革命性ZGC
  • OpenCV使用 GrabCut 算法进行交互式前景提取

    OpenCV使用 GrabCut 算法进行交互式前景提取 1 效果图 2 源码 参考 这篇博客将介绍如何使用Python OpenCV中的GrabCut 算法来提取图像中的前景 并为此创建一个交互式应用程序 1 效果图 官方示例 lena
  • 在vue3+setup+ts中使用内置动态组件component

    1 vue的内置组件的定义 component是vue的内置组件 不需要注册可以直接使用 通过is去选择要渲染的组件 可以是一个组件名称字符串 使用在选项式API中 也可以是组件的定义 使用在
  • 流程(待补充)

    start from init mlt rwlock 1 初始化mlt表的读写锁 函数体调pthread rwlock init mlt mlt lock NULL 该函数为C库提供 初始化该锁之后 后面可以加互斥锁修改mlt表的值 2 初
  • 离散数学——主析取范式与主合取范式原理探究

    主析取范式 对任意一个命题公式来说 主析取范式与主合取范式都是唯一的 命题变元指原子化的 P Q命题 极小项的定义 包含全部N个命题变元的合取式 称其为极小项 且N个命题变元中 每个变元与它的否定不能同时存在 但两者中必有一个出现且仅出现一
  • MakeFile编写

    1 生成静态库和动态库 文件 makefile test cpp test h lib PWD libs libtest a so PWD libs libtest so all lib so lib test o ar rcs lib t
  • JSP的基本使用

    开发工具与关键技术 IDEA 撰写时间 2022 8 18 前提 创建一个java Maven项目 并把 Tomcat 装上 在java Maven项目的 pox xml文件配置 JSP

随机推荐

  • docker和原生方式安装jenkins,以及常见问题踩坑

    前言 Jenkins 是一款开源自动化服务器 可用于轻松设置持续集成和持续交付 CI CD 管道 持续集成 CI 是DevOps的一种实践 团队成员定期将其代码更改提交到版本控制存储库 然后运行自动构建和测试 持续交付 CD 是一系列的实践
  • Docker网络模式

    目录 一 Docker网络的实现原理 二 Docker的五种网络模式 1 Host模式 2 Container模式 3 None模式 4 Bridge模式 默认 5 自定义网络模式 5 1 查看网络模式列表 5 2 查看容器信息 5 3 指
  • 解决 MySQL 中不能输入中文的问题,复制粘贴也不允许。

    解决 MySQL 中不能输入中文的问题 复制粘贴也不允许 首先 MySQL 中不能输入中文的问题与 MySQL 版本无关 与主机也无关 Debian centos 都无所谓 而我的 locale 下的语言设置都没问题 我这里的 MySQL
  • python项目结构设计_python工程结构

    在一个健康的开发周期中 代码风格 API设计和自动化是非常关键的 同样的 对于工程的架构 仓库的结构也是关键的一部分 当一个潜在的用户和贡献者登录到您的仓库页面时 他们会看到这些 工程的名字 工程的描述 一系列的文件 如果您的仓库的目录是一
  • const在指针赋值时候注意事项:assignment discards ‘const’ qualifier from pointer target type的解决方法

    const 与 define 都可以创建类似功能的符号常量 但是const可以创建const 数组 指针 指向const的指针 很重要的一点const能使不需要修改的数据变成只读的模式 include
  • java8 方法引用详解_Java8中如何通过方法引用获取属性名详解

    前言 在我们开发过程中常常有一个需求 就是要知道实体类中Getter方法对应的属性名称 Field Name 例如实体类属性到数据库字段的映射 我们常常是硬编码指定 属性名 这种硬编码有两个缺点 1 编码效率低 因为要硬编码写属性名 很可能
  • Linux系统shell脚本基础之while循环

    Linux系统shell脚本基础之while循环 一 脚本要求 二 脚本内容 1 脚本1 2 脚本2 三 执行脚本1结果 四 执行脚本2 一 脚本要求 脚本1 计算从1加到100的值 使用while循环 脚本2 输入一个数 输出1加到这个数
  • 网易游戏2011.10.15校园招聘会笔试题

    网易游戏2011 10 15校园招聘会笔试题 转载于 http blog csdn net hackbuteer1 article details 6878570 1 对于一个内存地址是32位 内存页是8KB的系统 0X0005F123这个
  • <mvc:default-servlet-handler />到底有什么用

    tomcat容器的web xml中有一个defaultServlet 用于处理静态资源 映射路径是 我们自定义的web xml最终相当于会与容器的web xml合并 而自定义DispatchServlet一般也是使用 导致容器中的defau
  • python安装报错error writing to file:......

    今天换了win10 64电脑 安装python3 6 8时 报错 error writing to file 安装时 右键 以管理员身份运行 安装成功 转载于 https www cnblogs com shuaishuaidefeizhu
  • linux启动时有文件错误,Linux 无法启动常见的几种原因及解决办法

    导致 Linux 无法启动的原因有很多 下面良许小编就将常见的几种原因及解决办法进行详述 希望对大家有所帮助 文件系统配置不当 如 etc inittab文件 etc fstab 文件等配置错误或丢失 导致系统出现故障 以至于无法启动 非法
  • 应急响应-钓鱼邮件的处理思路溯源及其反制

    0x00 钓鱼邮件的危害 1 窃取用户敏感信息 制作虚假网址 诱导用户输入敏感的账户信息后记录 2 携带病毒木马程序 诱导安装 使电脑中病毒木马等 3 挖矿病毒的传输 勒索病毒的传输等等 0x01 有指纹的钓鱼邮件的溯源处理 从邮件中获取相
  • buildroot添加新硬件内核支持

    1
  • 对开发来讲,业务重要还是技术重要?

    很多开发者为天天写业务代码无暇提升技术而焦虑 苦恼 比如 又如 又如 再如 那么 作为开发者 到底该怎么面对 写业务代码 这件事呢 今天我们就从以下几个方面聊聊这个话题 什么是业务 业务和技术的关系 业务和因解决业务而衍生的业务 对业务的态
  • Bitbucket代码迁移到Gitlab

    首先需要确定使用具有一定权限的账号进行迁移 然后在迁移的机器上配置git环境 添加账户信息 git config global user name XXX git config global user email XXX XXXX com
  • uni-app实现多选

  • word2016解决mathtype无法加载mathpage.wll文件问题

    参考文章 https www cnblogs com weiyouqing p 9082353 html 首先需要找到在Word加载的两个文件 一个是MathType Commands 6 For Word2010 dotm 文件位置 C
  • 拥塞控制算法

    TCP拥塞控制算法的目的可以简单概括为 公平竞争 充分利用网络带宽 降低网络延时 优化用户体验 然而就目前而言要实现这些目标就难免有权衡和取舍 算法分类 基于丢包策略的传统拥塞控制算法的几个迭代版本 如图所示 与此同时还有一类算法是基于RT
  • 计算机二级(Python)__第三方库

    Python第三方库依照安装方式灵活性和难易程度有3个方法 建议一次使用 这三个方法是 pip工具安装 自定义安装和文件安装 pip工具安装 最常用且最高效的Python第三方库安装方式采用pip工具安装 pip是Python官方提供并维护
  • spring深入学习(十九) IOC 之 Factory 实例化 bean

    这篇我们关注创建 bean 过程中的第一个步骤 实例化 bean 对应的方法为 createBeanInstance 如下 protected BeanWrapper createBeanInstance String beanName R