程序员

[源码]springboot中BeanWrapper的生成方法a

2019-11-23  本文已影响0人  Wayne维基

前言

上文在分析IOC中getBean方法
讲到getBean的整个调用逻辑是:
doGetBean-->getSingleton-->createBean-->createBeanInstance。
是一个获取不到就创建的逻辑(Lazy load)。

而createBeanInstance创建createBean,使用三种策略之一:

autowireConstructor

createBeanInstance的代码通过不同的条件选择调用autowireConstructor。

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

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

方法内部调用的ConstructorResolver中的autowireConstructor
ConstructorResolver类通过参数匹配方式来进行构造,是一种策略模式。调用的方法autowireConstructor用于生成需要的BeanWrapper(Bean的一个包装类,用于获取bean的一些属性)。
方法入参数

public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
            @Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
        // beanwrapper的默认实现
        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;
                if (constructorToUse != null && mbd.constructorArgumentsResolved) {
                    // Found a cached constructor...
                    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) {
                Class<?> beanClass = mbd.getBeanClass();
                try {
                    // public, protected, default (package) access, and private constructors
                    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);
                }
            }

            // 构造参数只有一个的情况
            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;
                }
            }

            // Need to resolve the constructor.
            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();
                minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
            }
            // 按照构造方法的访问权限级别和参数数量进行排序
            // public 到 non-public降序
            // 多参数到少参数 降序
            AutowireUtils.sortConstructors(candidates);
            int minTypeDiffWeight = Integer.MAX_VALUE;
            Set<Constructor<?>> ambiguousConstructors = null;
            LinkedList<UnsatisfiedDependencyException> causes = null;

            for (Constructor<?> candidate : candidates) {
                Class<?>[] paramTypes = candidate.getParameterTypes();

                if (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) {
                    // 找到了满足条件的构造函数,提前结束循环
                    // argsToUse.length > paramTypes.length这个是怎么来的呢?首先前面是排序过的,如果有多个构造函数能满足,优先选择到public和参数多的。参数少的,和权限低的就不用选择了。
                    // Already found greedy constructor that can be satisfied ->
                    // do not look any further, there are only less greedy constructors left.
                    break;
                }
                // 如果参数不足,那么也不用考虑了,直接跳过
                if (paramTypes.length < minNrOfArgs) {
                    continue;
                }

                ArgumentsHolder argsHolder;
                if (resolvedValues != null) {
                    try {
                        // 判断否则方法是否有 ConstructorProperties 注解,若有,则取注解中的
                        String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
                        if (paramNames == null) {
                            ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                            if (pnd != null) {
                                //  获取构造参数的名称,public fun(String a, int b),返回的就是[a, b]
                                paramNames = pnd.getParameterNames(candidate);
                            }
                        }
                        // 创建参数名称,其中会完成类型的转化
                        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 {
                    // Explicit arguments given -> arguments length must match exactly.
                    if (paramTypes.length != explicitArgs.length) {
                        continue;
                    }
                    argsHolder = new ArgumentsHolder(explicitArgs);
                }

                 // 计算每个参数类型与构造方法参数列表的差异,差异小的,说明是合适的构造方法
                // 这里typeDiffWeight可以看作一个相似度的度量
                // mbd.isLenientConstructorResolution() 条件。官方的解释是:返回构造方法的解析模式,有宽松模式(lenient mode)和严格模式(strict mode)两种类型可选。这两个类型的区别是什么,暂时不去考虑,以后有时间再看吧。todo
                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;
                }
                // 以上条件都无法选择出最好的构造方法,就放入ambiguousConstructors这个中,下面一个逻辑是说如果这个ambiguousConstructors不为空直接抛出异常,看来spring不会给出默认选择项啊,对于编程语言来说,严格更不容易出现莫名其妙的错,这样其实是很好的。
                else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
                    if (ambiguousConstructors == null) {
                        ambiguousConstructors = new LinkedHashSet<>();
                        ambiguousConstructors.add(constructorToUse);
                    }
                    ambiguousConstructors.add(candidate);
                }
            }

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

            if (explicitArgs == null && argsHolderToUse != null) {
                // 缓存信息,在别处使用       
                argsHolderToUse.storeCache(mbd, constructorToUse);
            }
        }

        Assert.state(argsToUse != null, "Unresolved constructor arguments");
        // instantiate最终创建了bean,默认是反射模式,如果包含 lookup-method 和 replace-method,则通过 CGLIB 增强 bean 实例
        bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
        return bw;
    }

小结

instantiate

看完上面的小结,知道beanInstance的核心逻辑在instantiate
这个方法如下:

private Object instantiate(
            String beanName, RootBeanDefinition mbd, Constructor<?> constructorToUse, Object[] argsToUse) {

        try {
            InstantiationStrategy strategy = this.beanFactory.getInstantiationStrategy();
            if (System.getSecurityManager() != null) {
                return AccessController.doPrivileged((PrivilegedAction<Object>) () ->
                        strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse),
                        this.beanFactory.getAccessControlContext());
            }
            else {
                return strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Bean instantiation via constructor failed", ex);
        }
    }

核心逻辑是:
InstantiationStrategy strategy = this.beanFactory.getInstantiationStrategy();
return strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);

通过策略模式,调用instantiate生成Object
spring中这个策略模式有个一个简单实现,在SimpleInstantiationStrategy中。代码如下:

    @Override
    public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
            final Constructor<?> ctor, Object... args) {

        if (!bd.hasMethodOverrides()) {
            if (System.getSecurityManager() != null) {
                // use own privileged to change accessibility (when security is on)
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    ReflectionUtils.makeAccessible(ctor);
                    return null;
                });
            }
            return BeanUtils.instantiateClass(ctor, args);
        }
        else {
            return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
        }
    }

其中return地方有两处:

BeanUtils.instantiateClass

看到这里,已经几乎是最底层的bean生成的逻辑,仿佛一个俄罗斯套娃,一层层拨开逻辑终于到了最内核的这部分。

public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
        Assert.notNull(ctor, "Constructor must not be null");
        try {
            ReflectionUtils.makeAccessible(ctor);
            return (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
                    KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
        }
        catch (InstantiationException ex) {
            throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
        }
        catch (IllegalAccessException ex) {
            throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
        }
        catch (IllegalArgumentException ex) {
            throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
        }
        catch (InvocationTargetException ex) {
            throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
        }
    }

其中:KotlinDelegate.instantiateClass(ctor, args)是Kotlin primary constructor,这个类这里先不介绍,以后有时间看。
更普遍的调用逻辑是:
ReflectionUtils.makeAccessible(ctor); // 这个ReflectionUtils是反射工具类
ctor.newInstance(args)

上一篇 下一篇

猜你喜欢

热点阅读