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> ambiguousConstructors = null;
        LinkedList 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) () ->
                    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) () -> {
                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 instantiateClass(Constructor 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()的详细拆分就到这里了

你可能感兴趣的:(spring容器之bean加载策略之构造函数注入模式)