spring容器之bean加载策略之构造函数注入模式

在上节spring容器之创建bean实例中我们看了# createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args)完成了bean的初始化,虽然那个方法有点长,但我们最后总结发现,spring是通过不同的策略模式来完成bean的初始化如:

  • 通过回调#obtainFromSupplier(final String beanName, final RootBeanDefinition mbd) 方法来初始化
  • 通过工厂方法的方式:#instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs)
  • 还有一种就是通过构造函数自动注入的方式:#autowireConstructor(final String beanName, final RootBeanDefinition mbd, Constructor<?>[] chosenCtors, final Object[] explicitArgs)来实现bean的初始化
  • 最后一种是默认构造函数的方式:#instantiateBean(final String beanName, final RootBeanDefinition mbd)的方法来实现bean的初始化工作

关于前面的两种我们已经说了,这里就不在重复了,我们来看后两种:

通过构造函数自动注入的方式
AbstractAutowireCapableBeanFactory.java
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用于bean实例的封装
    BeanWrapperImpl bw = new BeanWrapperImpl();
    //初始化bw
    this.beanFactory.initBeanWrapper(bw);
    //1.获取constructorToUse argsHolderToUse和argsToUse参数
    Constructor<?> constructorToUse = null;//所使用的的构造函数
    ArgumentsHolder argsHolderToUse = null;//构造参数
    Object[] argsToUse = null;
    //2.通过explicitArgs参数来决定实例化bean所使用的构造函数及构造参数
    //explicitArgs为通过getBean传入的,如果在调用的过程中指定构造函数和参数那么直接使用
    if (explicitArgs != null) {
        argsToUse = explicitArgs;
    }
    //2.1.这里表示没有指定那么会从配置文件中去解析获取
    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;
                }
            }
        }
        //2.2.如果缓存中
        //解析保存在beanDefinition中的参数
        //如给定方法的构造函数 A(int ,int ),则通过此方法后就会把配置文件中的("1","1")转换为 (1,1)
        //缓存中的值可能是原始值也有可能是最终值
        if (argsToResolve != null) {
            argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
        }
    }
    //2.3.没有被缓存
    if (constructorToUse == null || argsToUse == null) {
        // Take specified constructors, if any.

        //如果chosenCtors没有被传入,那么获取构造函数
        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);
            }
        }
        //2.4.使用默认的构造函数初始化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;
                }
                //封装初始化之后的bean
                bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
                return bw;
            }
        }

        // Need to resolve the constructor.
        //2.5.是否需要解析器
        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);
        }
        //3.对构造函数进行排序
        //public构造函数优先,非public次之
        AutowireUtils.sortConstructors(candidates);
        //最小参数的权重
        int minTypeDiffWeight = Integer.MAX_VALUE;
        Set<Constructor<?>> ambiguousConstructors = null;
        LinkedList<UnsatisfiedDependencyException> causes = null;
        //遍历candidates 获取构造函数的参数类型
        for (Constructor<?> candidate : candidates) {
            Class<?>[] paramTypes = candidate.getParameterTypes();
            // 如果已经找到选用的构造函数或者需要的参数个数小于当前的构造函数参数个数,则终止。
            //因为,已经按照参数个数降序排列了
            if (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) {
                // 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 {
                    //获取注解上的参数名称
                    String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
                    if (paramNames == null) {
                        //获取构造参数的探索器
                        ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                        if (pnd != null) {
                            //通过探测器获取参数名称
                            paramNames = pnd.getParameterNames(candidate);
                        }
                    }
                    //根据bean的名称和构造参数以及构造函数来创建参数持有者ArgumentsHolder对象
                    argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
                            getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
                }//如果是UnsatisfiedDependencyException异常则添加到causes中
                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;
                }
            }
            //resolvedValues为null的情况下
            else {
                // Explicit arguments given -> arguments length must match exactly.
                //构造函数没有参数的情况下
                if (paramTypes.length != explicitArgs.length) {
                    continue;
                }
                //通过explicitArgs来创建ArgumentsHolder
                argsHolder = new ArgumentsHolder(explicitArgs);
            }
            //isLenientConstructorResolution主要是判断解析构造函数的时候是否以宽松模式还是严格模式
            //严格模式:解析构造函数时,必须所有的都需要匹配,否则抛出异常
            //宽松模式:使用具有"最接近的模式"进行匹配
            //typeDiffWeight:类型差异权重
            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;
            }
            //类型差异权重等于参数最小权重,将constructorToUse进行保存
            else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
                if (ambiguousConstructors == null) {
                    ambiguousConstructors = new LinkedHashSet<>();
                    ambiguousConstructors.add(constructorToUse);
                }
                ambiguousConstructors.add(candidate);
            }
        }
        //没有可以执行的构造器函数或工厂方法,直接抛UnsatisfiedDependencyException异常
        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);
        }
        //4.将解析的参数进行保存
        if (explicitArgs == null && argsHolderToUse != null) {
            argsHolderToUse.storeCache(mbd, constructorToUse);
        }
    }

    Assert.state(argsToUse != null, "Unresolved constructor arguments");
    //5.实例化bean并封装在bw中
    bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
    return bw;
}

关于构造函数创建bean实例的过程中,我们发现跟#instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) 方法一样,关于详细部分这里不再深究可以去看我的上一篇文章,接下来我们看看一个重要的部分就是创建完的bean是如何完成初始化的过程.

初始化过程

在#autowireConstructor()方法的末尾我们看到的是最后将创建完的bean通过方法# instantiate(String beanName, RootBeanDefinition mb Constructor<?> constructorToUse, Object[] argsToUse)来实现的,跟踪代码发现:

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

该方法我们在上篇文章中讲过了这里不再啰嗦,发现这里并不是真正的核心处理方法,接着看:

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;
            });
        }
        //1.通过 BeanUtils直接使用构造器对象实例化Bean对象
        return BeanUtils.instantiateClass(ctor, args);
    }
    else {
        //2初始化CGLB对象
        return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
    }
}

在该方法中,首先设置对访问权限的设置,首先是通过构造器来实例化bean对象

  BeanUtils.java
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) {
                    //如果参数是isPrimitive类型的,保存其对应的值在argsWithDefaultValues数组中
                    Class<?> parameterType = parameterTypes[i];
                    argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
                }
                //用来构建实例的参数不为null时
                else {
                    argsWithDefaultValues[i] = args[i];
                }
            }
            //通过够构造函数来创建对象
            return ctor.newInstance(argsWithDefaultValues);
        }
    }
    //对各种异常进行封装,统一抛出BeanInstantiationException异常
    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());
    }
}

上述方法主要是通过构造函数来创建对象,主要的区别在于:

  • 如果我们传入的构造参数存在,则直接创建
  • 反之是对构造参数的解析获取,最后利用反射和内省机制来构建bean实例

在2我们可以看到是初始化cglb实例,接着看:

protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName,
        BeanFactory owner, @Nullable Constructor<?> ctor, Object... args) {

    throw new UnsupportedOperationException("Method Injection not supported in SimpleInstantiationStrategy");
}

该方法为空实现,主要是由子类org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy 来实现,具体来看代码:

CglibSubclassingInstantiationStrategy.java
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
    return instantiateWithMethodInjection(bd, beanName, owner, null);
}

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

    // Must generate CGLIB subclass...
    //<>生成一个CGLB子类对象
    return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);
}


/**
 * An inner class created for historical reasons to avoid external CGLIB dependency
 * in Spring versions earlier than 3.2.
 */
private static class CglibSubclassCreator {

    private static final Class<?>[] CALLBACK_TYPES = new Class<?>[]
            {NoOp.class, LookupOverrideMethodInterceptor.class, ReplaceOverrideMethodInterceptor.class};

    private final RootBeanDefinition beanDefinition;

    private final BeanFactory owner;

    CglibSubclassCreator(RootBeanDefinition beanDefinition, BeanFactory owner) {
        this.beanDefinition = beanDefinition;
        this.owner = owner;
    }

上述为创建CGLB实例的过程,在<>处我们可以看到还是通过#instantiate(@Nullable Constructor<?> ctor, Object... args)方法来完成实例的初始化过程,代码如下:

/**
     * Create a new instance of a dynamically generated subclass implementing the
     * required lookups.
     * @param ctor constructor to use. If this is {@code null}, use the
     * no-arg constructor (no parameterization, or Setter Injection)
     * @param args arguments to use for the constructor.
     * Ignored if the {@code ctor} parameter is {@code null}.
     * @return new instance of the dynamically generated subclass
     */
    public Object instantiate(@Nullable Constructor<?> ctor, Object... args) {
        //创建一个cglb的代理类
        Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
        Object instance;
        //如果当前构造器不存在,通过BeanUtils调用默认构造器来创建
        if (ctor == null) {
            instance = BeanUtils.instantiateClass(subclass);
        }
        else {
            try {
                //获取代理对象的构造器
                Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
                //创建实例
                instance = enhancedSubclassConstructor.newInstance(args);
            }
            catch (Exception ex) {
                throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
                        "Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
            }
        }
        // SPR-10785: set callbacks directly on the instance instead of in the
        // enhanced class (via the Enhancer) in order to avoid memory leaks.
        Factory factory = (Factory) instance;
        factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
                new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
                new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
        return instance;
    }

在获代码中我们可以看到,创建CGLB对象的过程,首先是获取代理对象,如果当前构造器不存在则则使用默认无参的,最后完成bean的创建,这就是关于CGLB实例创建的过程

小结

关于#createBeanInstance()的过程,spring对于不同创建都会选择其对应的策略模式来完成,关于策略模式有以下几种:

  • 通过Supplier回调方式的方式来实现bean的创建
  • 通过工厂方法来完成bean的创建
  • 通过构造器自动注入的方式来完成bean的创建
  • 最后一种是通过默认构造器的方式

在以上4中的策略模式中,其中工厂方法和构造器自动注入的方式最为复杂,简友们可以仔细的看看,哈哈哈,代码有点长哦!其两者的方式很接近,当然我们在最后衍生出了CGLiB实例的创建的过程,发现spring是通过#bd.hasMethodOverrides()来判断是否有覆盖的方法,如果有则只能通过cglib的方式来实例化,反之利用反射的方式来创建.

关于createBeanInstance()的详细拆分就到这里了

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,376评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,126评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,966评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,432评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,519评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,792评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,933评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,701评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,143评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,488评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,626评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,292评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,896评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,324评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,494评论 2 348

推荐阅读更多精彩内容