【六】Spring IoC 最全源码详解之bean实例化过程

版权声明:本博客原创文章遵循CC BY-NC-SA 2.5 CN 协议 https://blog.csdn.net/wuyuwei/article/details/87557629

如果将Spring初始化过程中创建bean之前的准备工作比喻成生命从无到有,从单细胞生命变为多细胞生命,从海洋蔓延到陆地,从……的话,那么本章即将介绍的bean实例化过程就是寒武纪生命大爆发!


目录

1.getBean

2.createBean

3.createBeanInstance

3.1 寻找构造函数进行实例化

3.1.1 利用默认构造函数实例化

3.1.2 利用带参构造函数实例化

4.相亲算法

5. 附录:本项目工程文件


本节介绍bean实例化过程。对应执行的方法是finishBeanFactoryInitialization(beanFactory),中间跳过的国际化和事件监听器注册与初始化的步骤后续再专门写文章补充。本章节撰写时长12小时,建议阅读时常:6小时。去趟卫生间,等你回来我们就开始吧。

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
            beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
        beanFactory.setConversionService(
                beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }

    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }

    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
    }
    
    beanFactory.setTempClassLoader(null);
    // “冻结”住所有已经注册在bean工厂中的bd元数据,避免被改变了。
    beanFactory.freezeConfiguration();
    // 真正的干货所在
    beanFactory.preInstantiateSingletons();
}

preInstantiateSingletons()方法主要可以分两个阶段:1.对所有非lazy的bean进行创建;2.执行某些特殊bean创建完成后的回调方法。

public void preInstantiateSingletons() throws BeansException {
    if (logger.isTraceEnabled()) {
        logger.trace("Pre-instantiating singletons in " + this);
    }

    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
    // 遍历所有beanName,对所有的non-lazy且singletonbean进行创建,已经创建的不会再次执行。
    for (String beanName : beanNames) {
    	// 该方法的merge是指如果bean类继承有父类,那么就将它所有的父类的bd融合成一个RootBeanDefinition返回
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        //bean不是抽象的,没有@Lazy注解,并且还是单例的
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            //如果是FactoryBean,前面文章有提到过,FactoryBean的名字命名规则是:& + 普通beanName,获取到正确的名称后才能做getBean(beanName)这一步
            if (isFactoryBean(beanName)) {
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                if (bean instanceof FactoryBean) {
                    final FactoryBean<?> factory = (FactoryBean<?>) bean;
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                                        ((SmartFactoryBean<?>) factory)::isEagerInit,
                                getAccessControlContext());
                    }
                    else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                ((SmartFactoryBean<?>) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        getBean(beanName);
                    }
                }
            }
            else {
                getBean(beanName);
            }
        }
    }

    // 完成所有bean的创建过程后,执行实现了SmartInitializingSingleton接口bean的afterSingletonsInstantiated回调方法。
    // org.springframework.boot.autoconfigure.condition.BeanTypeRegistry会清空bdmap
    for (String beanName : beanNames) {
        Object singletonInstance = getSingleton(beanName);
        if (singletonInstance instanceof SmartInitializingSingleton) {
            final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    smartSingleton.afterSingletonsInstantiated();
                    return null;
                }, getAccessControlContext());
            }
            else {
                smartSingleton.afterSingletonsInstantiated();
            }
        }
    }
}
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

首先从bean工厂的bdmap中拿到所有的beanName,然后对其中能实例化的bean进行创建。getMergedLocalBeanDefinitio(beanName)是后续中经常会用到的方法,它的作用是从本bd出发,合并继承路径上的所有bd,合并完成后还要将合成后的mergeBd存放到bean工厂的mergedBeanDefinitions map结构中。

RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

不是抽象类,不是单例,还不是延迟加载的bean,才可以在Spring启动过程中被创建。确认该bean可以被创建后,还要判断该bean是FactoryBean还是普通bean。如果是FactoryBean,那么就走FactoryBean自己的生产逻辑。如果是普通bean,那么就走Spring实例化bean的默认逻辑,不管怎样,都需要走getBean(String name)-->doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly)方法。下面我们来看doGetBean方法,由于函数体很长,这里对不重要的try..catch分支进行了删减。

1.getBean

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
        @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

    // 普通bean直接去beanName, FactoryBean取去掉'&'前缀的beanName
    final String beanName = transformedBeanName(name);
    Object bean;    
    // 首先尝试去bean工厂singletonObjects容器中获取bean对象。
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        // 从bean工厂获取bean
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    //走else分支说明之前该bean之前还未创建过
    else {
        // Spring无法处理循环依赖对象是prototype类型的问题。
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            
            String nameToLookup = originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                        nameToLookup, requiredType, args, typeCheckOnly);
            }
            else if (args != null) {                
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else if (requiredType != null) {                
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
            else {
                return (T) parentBeanFactory.getBean(nameToLookup);
            }
        }

        //将beanName标记到baen工厂的alreadyCreated的Set中,保证不会重复创建该bean
        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }

        try {
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            // 注解@DependsOn。 A->B->C,则先注册和实例化C,然后是B,最后是A
            // 以本项目为例,当创建class Human的bean时,dependsOn数组中会存放"xiawa",因为Human @DepensOn("xiawa")
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                for (String dep : dependsOn) {
                    // 确定指定的依赖bean是否已注册为依赖于给定bean或其传递依赖项。
                    if (isDependent(beanName, dep)) {
                        throw new xxx;
                    }
                    // 尝试注册依赖的bd,如果已经创建则直接返回
                    registerDependentBean(dep, beanName);
                    //尝试先将依赖的bean创建出来,如果已经创建则直接从容器中获取
                    getBean(dep);
                }
            }

            // 创建单例对象.
            // 重点方法
            if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {
                        destroySingleton(beanName);
                        throw ex;
                    }
                });
                // 从容器中获取刚刚创建好的bean
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }
            // 原型对象的bean创建
            else if (mbd.isPrototype()) {
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

            else {
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                Object scopedInstance = scope.get(beanName, () -> {
                    beforePrototypeCreation(beanName);
                    try {
                        return createBean(beanName, mbd, args);
                    }
                    finally {
                        afterPrototypeCreation(beanName);
                    }
                });
                bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
            }
        }
        catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }

    // 返回bean前做最后的类型检查和转换
    if (requiredType != null && !requiredType.isInstance(bean)) {
        T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
        return convertedBean;
    }
    return (T) bean;
}

首先通过transformedBeanName(name)进行命名转换,主要针对FactoryBean的名称转换。然后尝试去bean工厂singletonObjects容器中获取已经缓存好的bean实例,拿不到再去走正在的创建流程。

这种以空间换时间的思想在整个Spring框架中展现的淋漓尽致,小到属性,大到bd,乃至bean实例都无一例外的先查缓存,尽量做到一次解析,多次使用。这和Java的“一次编译,处处运行”的理念交相辉映,相得益彰。

能获取到的执行流程非常简单,留给读者自己分析吧。那么现在进入长长的else分支,第一个if块是和循环依赖相关的组件。后续会有专门分析循环依赖的文章,再重点分析,这里暂时先跳过。简单知道Spring无法处理prototype的循环依赖就行了。接下来是一段关于ParentBeanFactory的场景,如果用户没有指定过bean工厂的层级关系,parentBeanFactory值就是null。ParentBeanFactory场景的这块代码并不难度,但是疏于本人从未指定过BeanFactory的层级关系项目,故这里暂时不急于分析,后续如有用到再回来补充。parentBeanFactory=null,相关的if语句块不会进入,流程继续望下走。typeCheckOnly=false是入参,markBeanAsCreated方法会执行。它的主要用途是在bean工厂的alreadyCreated集合中添加beanName,表示beanName已经创建了。

接下来进入try语句块,首先获取当前正在初始化bean的@DepensOn。比如本项目中,Human类依赖Eve类。所以要遍历依赖项,先将依赖的bean率先创建出来才行。嵌套执行的getBean(dep)方法就在说明这个问题。if (mbd.isSingleton()){...}语句块中是本文的主流程,它负责创建singleton的bean对象。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    synchronized (this.singletonObjects) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            // 如果当前正在创建的bean还处在另外线程的删除流程中。那就停止创建并抛出异常。
            if (this.singletonsCurrentlyInDestruction) {
                throw new 我都在被销毁了,还创建我干啥?!;
            }
            // 将正在创建的bean加入到Set<String> singletonsCurrentlyInCreation中
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<>();
            }
            try {
                // 调用传入的lambda方法。实际上就是调用createBean(beanName, mbd, args);
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            catch (Exception ex) {
                throw dosomething();
            }
            finally {
                // 将正在创建的bean从Set<String> singletonsCurrentlyInCreation中移除
                afterSingletonCreation(beanName);
            }
            // <beanName, beanObj>添加到bean工厂的singletonObjects中。
            if (newSingleton) {
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}

核心方法是singletonObject = singletonFactory.getObject();也就是调用传入lambda表达式中的核心方法createBean获得创建好的bean,然后addSingleton(beanName, singletonObject)将其添加到bean工厂中管理。

// <beanName, obj>加入到bean工厂的singletonObjects容器, 将beanName添加到单例对象List中。
// 其余的工作就是打扫卫生了。
protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
        this.singletonObjects.put(beanName, singletonObject);
        this.singletonFactories.remove(beanName);
        this.earlySingletonObjects.remove(beanName);
        this.registeredSingletons.add(beanName);
    }
}

另外当前bean是否处在另外线程的销毁流程中,如果是则停止创建该bean。在调用createBean的前后,分别调用beforeSingletonCreation(beanName)和afterSingletonCreation(beanName),实现在bean工厂的Set<String> singletonsCurrentlyInCreation集合中标记当前bean是否处在创建的过程。

2.createBean

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {    
    RootBeanDefinition mbdToUse = mbd;
    //从bd中解析出bean的Class
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }
    // 对重写方法的准备和校验
    mbdToUse.prepareMethodOverrides();     
    
    Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
    if (bean != null) {
        return bean;
    }
    //实例化和初始化对象的核心方法doCreateBean
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);        
    return beanInstance;
}

creatBean方法的实际执行是Object beanInstance = doCreateBean(beanName, mbdToUse, args);在此之前还做了几件事,唯一值得一提的是执行Object bean = resolveBeforeInstantiation(beanName, mbdToUse);方法。

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                // 调用before方法实现用户自定义的bean实例化方法
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    // 调用after方法实现用户自定义的依赖注入和自动装配方法
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}

如果项目中有实现InstantiationAwareBeanPostProcessors接口, 调用其对应的bean后置处理器的postProcessBeforeInstantiation和postProcessAfterInstantiation方法自主干预Spring的实例化过程。其中before是实现bean的实例化,after是实现bean的依赖注入和自动装配。 默认情况下Spring内部的bean后置处理器实现的postProcessBeforeInstantiation方法都是返回null,postProcessAfterInstantiation也都是返回传入的bean。一旦用户自定义实现了该方法返回了具体的对象而不是null,那么意味着Spring自身的bean创建流程到此被阻断,将提前返回用户自主创建的bean对象给上层。到目前为止,本人还从未使用过或者看到有人实例化过该方法。慎用!

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
        throws BeanCreationException {
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }

    // 从BeanWrapper获得封装在它内部的bean和bean类型
    final Object bean = instanceWrapper.getWrappedInstance();
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }
    // 调用实现了MergedBeanDefinitionPostProcessor的bean后置处理器的postProcessMergedBeanDefinition方法。
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                //CommonAnnotationBeanPostProcessor, AutowiredAnnotationBeanPostProcessor, ApplicationListenerDetector会被回调postProcessMergedBeanDefinition方法执行各自的逻辑。
                // CommonAnnotationBeanPostProcessor处理@PostConstruct 和 @PreDestroy方法添加到org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#lifecycleMetadataCache CurrentHashMap中。
                // 并且如果有就分别注册到bd的externallyManagedInitMethods和externallyManagedDestroyMethods Set集合中。
                // org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition是再次进行bd的融合。
                // 通过clazz.getDeclaredFields()得到bean中所有的属性字段和方法。然后挨个对其进行解析转换成metadata,最终放入到AutowiredAnnotationBeanPostProcessor#injectionMetadataCache中。
                // AutowiredAnnotationBeanPostProcessor会进行
                // ApplicationListenerDetector很简单,将beanName和是否是singleton的boolean变量放到ApplicationListenerDetector对象的Map<String, Boolean> singletonNames中。
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            catch (Throwable ex) {
                throw new xxx;
            }
            // 标记该bd已经合并处理完成了
            mbd.postProcessed = true;
        }
    }
    // 加入到bean工厂的earlySingletonObjects中,这个是Spring用来解决循环依赖的凭据(后续文章单独介绍)
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
            isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {        
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }    
    Object exposedObject = bean;
    try {
        // Spring进行依赖注入,也就是属性填充的地方。populate是落户于...的意思。Spring的开发者用这个词拟人化后非常贴切且让人感慨!    
        // 用bean定义中的属性值填充给定BeanWrapper中的bean实例。    
        populateBean(beanName, mbd, instanceWrapper);
        // bean属性填充完成后,就可以进行bean的初始化工作了。依赖注入初始化工作后续文章再详细介绍。
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    catch (Throwable ex) {
        throw new xxx;
    }

    if (earlySingletonExposure) {
        Object earlySingletonReference = getSingleton(beanName, false);
        if (earlySingletonReference != null) {
            if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
            }
            else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                String[] dependentBeans = getDependentBeans(beanName);
                Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                for (String dependentBean : dependentBeans) {
                    if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                        actualDependentBeans.add(dependentBean);
                    }
                }
                if (!actualDependentBeans.isEmpty()) {
                    throw new xxx;
                }
            }
        }
    }
    // 注册实现了DisposableBean接口的bean,该bean实现了void destroy()接口,在bean的生命周期销毁前可以触发回调进行善后工作。
    // 需要注意的是,它对原型对象无效。
    try {
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
        throw new xxx;
    }
    return exposedObject;
}

doCreateBean是bean创建的核心方法。它大体上可以分成两个步骤:1.bean实例化;2.bean初始化。bean实例化是调用createBeanInstance方法,最终通过反射创建出对象。bean的初始化是通过populateBean(beanName, mbd, instanceWrapper)和initializeBean(beanName, exposedObject, mbd)实现的。本文主要关注bean实例化流程,bean的初始化流程下一篇文章再详细分析。

3.createBeanInstance

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    Class<?> beanClass = resolveBeanClass(mbd, beanName);

    // 与响应式编程相关?待论证。
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beanName);
    }

    // 旧版本的Spring可以通过xml配置 <bean id='A' class='xxx' factory-method='getA'>从而获得静态的工厂方法获得bean A。
    if (mbd.getFactoryMethodName() != null) {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    // 如果之前已经解析过,就不用再去解析一遍了。RootBeanDefinition.resolvedConstructorOrFactoryMethod专门用来缓存构造函数,constructorArgumentsResolved用来存放构造是有参还是无参。
    // 有参走autowireConstructor,无参走instantiateBean
    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) {
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
            return instantiateBean(beanName, mbd);
        }
    }

    // 检查所有的SmartInstantiationAwareBeanPostProcessor,为指定bean确定一个构造函数。
    // 实际上就是org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors来负责。
    // 如果找到了构造函数,或者该bean是通过“AUTOWIRE_CONSTRUCTOR”按构造器自动装配,或者如果此bean定义了构造函数参数值,或者传入的构造参数不为空。
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    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);
    }
    // 走默认构造函数实例化bean
    return instantiateBean(beanName, mbd);
}

进入到bean实例化方法体。

if (mbd.getFactoryMethodName() != null) {
	return instantiateUsingFactoryMethod(beanName, mbd, args);
}

instantiateUsingFactoryMethod与静态的工厂方法相关。旧版本的Spring可以通过xml配置 <bean id='A' class='xxx' factory-method='getA'>从而获得静态的工厂方法获得bean A。

如果之前已经解析过构造函数且有缓存存在,就不用再去解析一遍了,直接根据解析的结果进入autowireConstructor(beanName, mbd, null, null)或是instantiateBean(beanName, mbd)方法实例化对象。其中RootBeanDefinition.resolvedConstructorOrFactoryMethod专门用来缓存构造函数,constructorArgumentsResolved用来存放构造是有参还是无参。

3.1 寻找构造函数进行实例化

假如没有找到缓存值,那就不得不开始解析了。determineConstructorsFromBeanPostProcessors(beanClass, beanName)方法内部通过循环所有bean后置处理器,最终通过AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors来负责这一项艰巨的工作

Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);

// determineConstructorsFromBeanPostProcessors实际调用的是public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
        throws BeanCreationException {
    // 在beanClass及其继承的父类中寻找@Lookup注解方法。
    if (!this.lookupMethodsChecked.contains(beanName)) {
        ReflectionUtils.doWithMethods(beanClass, method -> {
            Lookup lookup = method.getAnnotation(Lookup.class);
            if (lookup != null) {                    
                LookupOverride override = new LookupOverride(method, lookup.value());

                RootBeanDefinition mbd = (RootBeanDefinition) this.beanFactory.getMergedBeanDefinition(beanName);
                mbd.getMethodOverrides().addOverride(override);
            }
        });
        // 记录已经检查过的beanName,避免重复检查。
        this.lookupMethodsChecked.add(beanName);
    }
    // 双重检查老套路,先查看缓存中是否存在之前已经找到的构造函数。
    Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);    
    if (candidateConstructors == null) {        
        synchronized (this.candidateConstructorsCache) {
            candidateConstructors = this.candidateConstructorsCache.get(beanClass);            
            if (candidateConstructors == null) {
                // 首先通过beanClass.getDeclaredConstructors()获得所有的构造函数到rawCandidates数组
                Constructor<?>[] rawCandidates;
                rawCandidates = beanClass.getDeclaredConstructors();

                List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
                Constructor<?> requiredConstructor = null;
                Constructor<?> defaultConstructor = null;
                // 针对Kotlin语言的的,不用管。 Java语言没主构造函数一说。
                Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
                int nonSyntheticConstructors = 0;
                 
                for (Constructor<?> candidate : rawCandidates) {
                    // 下面的if判断语句可以简单理解成该构造方法并不是由内部类提供的。
                    if (!candidate.isSynthetic()) {
                        nonSyntheticConstructors++;
                    }
                    else if (primaryConstructor != null) {
                        continue;
                    }
                    // 看看这个候选的构造函数是不是加上了@Autowired 或者 @Value注解,一般情况下都是null。
                    AnnotationAttributes ann = findAutowiredAnnotation(candidate);
                    if (ann == null) {
                        //还有userClass不等于传入的beanClass的情况?这里看不懂。不过不影响后续的分析,因为还从未进入过该if分支。
                        Class<?> userClass = ClassUtils.getUserClass(beanClass);
                        if (userClass != beanClass) {
                            try {
                                Constructor<?> superCtor =
                                        userClass.getDeclaredConstructor(candidate.getParameterTypes());
                                ann = findAutowiredAnnotation(superCtor);
                            }
                            catch (NoSuchMethodException ex) {
                                // Simply proceed, no equivalent superclass constructor found...
                            }
                        }
                    }
                    // 如果构造函数上有注解,则加到candidates中。
                    if (ann != null) {
                        boolean required = determineRequiredStatus(ann);
                        if (required) {                            
                            requiredConstructor = candidate;
                        }
                        // candidates唯一可以添加的地方。也就是正在被解析的构造函数上有注解。
                        candidates.add(candidate);
                    }
                    // 没有入参的构造函数就是默认构造函数
                    else if (candidate.getParameterCount() == 0) {
                        defaultConstructor = candidate;
                    }
                }

                if (!candidates.isEmpty()) {
                    if (requiredConstructor == null) {
                        if (defaultConstructor != null) {
                            candidates.add(defaultConstructor);
                        }
                        else if (candidates.size() == 1 && logger.isInfoEnabled()) {
                            logger.info("Inconsistent constructor declaration on bean with name '" + beanName +
                                    "': single autowire-marked constructor flagged as optional - " +
                                    "this constructor is effectively required since there is no " +
                                    "default constructor to fall back to: " + candidates.get(0));
                        }
                    }
                    candidateConstructors = candidates.toArray(new Constructor<?>[0]);
                }                
                // 如果Class的构造方法只有一个,并且构造方法的入参还不为0。 将其作为候选结果。
                else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
                    candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
                }
                // 如果如果Class的构造方法有且只有2个,并且拥有primaryConstructor构造函数。与Kotlin相关,略过。
                else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
                        defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
                    candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
                }
                // 与Kotlin相关,略过
                else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
                    candidateConstructors = new Constructor<?>[] {primaryConstructor};
                } //如果上述条件都不满足,则创建一个Constructor对象,该对象的初始值是0,仅仅起到一个占位作用。
                else {
                    candidateConstructors = new Constructor<?>[0];
                }
                // 缓存构造方法
                this.candidateConstructorsCache.put(beanClass, candidateConstructors);                
            }
        }
    }
    return (candidateConstructors.length > 0 ? candidateConstructors : null);
}

1.在beanClass及其继承的父类中寻找@Lookup注解方法,如果存在则更新bd。最后将该方法加入到AutowiredAnnotationBeanPostProcessor的lookupMethodsChecked集合中,代表这些bean已经寻找过@Lookup,不用再重复解析了。@Lookup方法的作用和使用方法可以参考《关于Spring自动装配几个你所不知道的事》中的第3小节内容。

2.在缓存中看看构造函数是否解析,如果不存在代表需要解析。通过beanClass.getDeclaredConstructors();该Class的构造函数。以Human.class为例,获取的结果是就一个带参的自定义构造函数。

public com.Hodey.learn.bean.Human(java.lang.String)

3.遍历这些构造函数,非内部类的构造函数会nonSyntheticConstructors++,Kotlin语言的primaryConstructor直接跳过,因为我们仅分析java语言。如果构造函数上有注解@Autowired或@Value,则需要进行一些单独的处理,就不深入分析了。这里直接给出代码分析结论:创建的类当且仅当Class中有且仅有一个带参的构造方法,才返回找到的这个带参构造方法,否则都返回null。

 Synthetic是什么? Synthetic是java的一个关键字,编译器在编译过程中引入的。 非静态内部类被编译后,会在其方法前加上synthetic,表面是来自内部类,和外部类加以区分。 

最终寻找构造函数Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);结束后,根据ctors有无内容就分为两种情况:1.通过带参的构造函数执行bean实例化过程autowireConstructor(beanName, mbd, ctors, args); 2.没有找到构造函数就走默认构造函数instantiateBean(beanName, mbd)实例化bean的过程。

3.1.1 利用默认构造函数实例化

我们先来看相对简单的用默认构造函数实例化的过程instantiateBean(beanName, mbd)。去掉相关的安全检查部分,代码简化如下:

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
    try {
        Object beanInstance;
        final BeanFactory parent = this;
        // 调用SimpleInstantiationStrategy#instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner)方法进行实例化
        beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);    
        // 将实例化后的对象封装到BeanWrapper结构中
        BeanWrapper bw = new BeanWrapperImpl(beanInstance);
        initBeanWrapper(bw);
        return bw;
    }
    catch (Throwable ex) {
        throw new xxx;
    }
}

beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);方法是调用的SimpleInstantiationStrategy#instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner)方法进行实例化。实例化完成后将得到的beanInstance封装到BeanWrapperImpl对象bw中,返回给上层。注意:initBeanWrapper(bw)方法并不是对bean实例进行初始化,仅仅是初始化BeanWrapperImpl对象。其实封装了并没什么卵用,待会儿返回上层还需要解封出来。下面来看instantiate方法:

public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
    if (!bd.hasMethodOverrides()) {
    	// 存放待会儿实例化用到的构造函数
        Constructor<?> constructorToUse;
        synchronized (bd.constructorArgumentLock) {
            constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
            if (constructorToUse == null) {
                final Class<?> clazz = bd.getBeanClass();
                
                try {
                    // 获取默认构造函数
                    constructorToUse = clazz.getDeclaredConstructor();
                    // 设置到bd的缓存上,下次来就不用解析了
                    bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                }
                catch (Throwable ex) {
                    throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                }
            }
        }
        // 执行实例化
        return BeanUtils.instantiateClass(constructorToUse);
    }
    else {
        // Must generate CGLIB subclass.
        return instantiateWithMethodInjection(bd, beanName, owner);
    }
}

首先Class<?> clazz = bd.getBeanClass()拿到clazz,然后再constructorToUse = clazz.getDeclaredConstructor()默认构造函数并将其设置在bd.resolvedConstructorOrFactoryMethod上缓存。最后调用BeanUtils.instantiateClass(constructorToUse);实例化出bean对象出来。

public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {

    try {
        ReflectionUtils.makeAccessible(ctor);
        return (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
                KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
    }
    catch (Exception ex) {
        throw new xxx;
    }
}

最后通过ctor.newInstance(args)反射出对象。KotlinDelegate是针对Kotlin语言的方法。到此一个bean就被实例化出来了。

Java反射机制提供的setAccessible(true)方法可以取消Java的权限控制检查:
1. 使得非public的变量和方法可以被调用到。
2. 让JVM忽略大量的访问控制检查,提高反射速度。

随后一路向上返回,在instantiateBean方法中封装成BeanWrapperImpl对象继续返回上层,最终返回到doCreateBean方法的第二个语句块中的instanceWrapper = createBeanInstance(beanName, mbd, args);执行完成。接下来又从BeanWrapperImpl解封出bean对象和bean的类型beanType。再接着执行:

1.applyMergedBeanDefinitionPostProcessors方法;

2.将bean缓存在bean工厂的earlySingletonObjects中;

3.完成bean依赖注入和初始化;

4.注册bean销毁的回调接口。

之后返回createBean中做一些简单的类型校验检查然后返回getSingleton方法,singletonObject = singletonFactory.getObject();执行完毕。最后通过addSingleton(beanName, singletonObject);将创建好的bean添加到bean工厂中就完成了bean的创建过程。以上就是使用默认构造函数实例化bean的全过程。

3.1.2 利用带参构造函数实例化

让我们回到createBeanInstance方法。

Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
		mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
	return autowireConstructor(beanName, mbd, ctors, args);
}

当determineConstructorsFromBeanPostProcessors方法确定的构造函数ctors不为空时就会调用autowireConstructor进行带参的构造函数实例化。

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

    BeanWrapperImpl bw = new BeanWrapperImpl();
    this.beanFactory.initBeanWrapper(bw);

    //constructorToUse 存放匹配到构造函数
    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) {
        // 上一步确定好的构造方法给到candidates
        Constructor<?>[] candidates = chosenCtors;
        if (candidates == null) {
            Class<?> beanClass = mbd.getBeanClass();

            candidates = (mbd.isNonPublicAccessAllowed() ?
                    beanClass.getDeclaredConstructors() : beanClass.getConstructors());            
        }
        // 假如仅有一个构造方法,并且该构造方法的参数还是0。那么就直接调用instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS)进行实例化,实例化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;
            }
        }

        // 约定优于配置,默认是AUTOWIRE_NO,
        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);
        }

        // 1.public的方法放前面
        // 2.形参多的方法放前面
        AutowireUtils.sortConstructors(candidates);
        // 与心中候选对象的差异值
        int minTypeDiffWeight = Integer.MAX_VALUE;
        // 备胎集合
        Set<Constructor<?>> ambiguousConstructors = null;
        // 吐槽树洞
        LinkedList<UnsatisfiedDependencyException> causes = null;

        for (Constructor<?> candidate : candidates) {
            // 获得构造函数所在类的类型
            Class<?>[] paramTypes = candidate.getParameterTypes();

            // 找到了满足要求的郎君就break。
            if (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) {
                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) {
                            // 得到beanClass的构造参数名称。
                            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);
                    }
                    // 没有找到就抛出异常,将异常加入到causes链表中,赶紧匹配一个candidata。
                    // 如果所有candidata都找完了还没找到合适的对象,才抛出异常,告诉爸妈相亲失败。
                    if (causes == null) {
                        causes = new LinkedList<>();
                    }
                    causes.add(ex);
                    continue;
                }
            }
            else {
                // 初始条件就不够,赶紧跳过选下一个.
                if (paramTypes.length != explicitArgs.length) {
                    continue;
                }
                argsHolder = new ArgumentsHolder(explicitArgs);
            }

            // 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;
            }
            // 遇到两个大汉的条件一样优秀,那就不好办了。暂时加入到ambiguousConstructors这个代表摸棱两可的Set中。
            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 没找到如意郎君;
        }
        else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
            throw new 挑花了眼,不知道选谁;
        }

        // 将挑选好的构造方法和对应的构造参数放到bd中。
        if (explicitArgs == null && argsHolderToUse != null) {
            argsHolderToUse.storeCache(mbd, constructorToUse);
        }
    }

    // 实例化对象,并缓存。之后的bean实例化的流程与使用默认构造实例化bean的流程一样了。
    bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
    return bw;
}

constructorToUse和argsToUse分别用于存放实例化bean要用的构造函数和构造函数的入参。先通过入参或缓存的构造函数入参尝试对argsToUse进行赋值,为null就需要进行解析。Constructor<?>[] candidates = chosenCtors;把构造函数放入candidates中。并且构造函数为null的话,还要 通过Class搭桥获得默认的构造方法(该步骤中已经不是Java代码的流程,本小节不加区分的分析Java和Kotlin代码,以求展现作者的精髓)。另外,构造函数的入参ArgumentsHolder argsHolder获取是通过createArgumentArray方法中实现的,由于该内容与bean的依赖注入内容相重合,所以我们留到下一篇文章再讲。

Constructor<?>[] candidates = chosenCtors;
if (candidates == null) {
        Class<?> beanClass = mbd.getBeanClass();

        candidates = (mbd.isNonPublicAccessAllowed() ?
                beanClass.getDeclaredConstructors() : beanClass.getConstructors());            
}

如果构造方法只有一个,并且还没有入参。这个就和默认构造方法没什么区别了,所以赶紧调用bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));方法实例化bean得了,这个分支过程可参考3.1.1节内容,不再赘述。

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

接下来就是尝试去确定最小参数个数。默认是0,如果能确定出参数个数>0的话,可以在后续的循环中提高一点效率。接下来就是对candidates进行排序了,排序原则是:public>protected>private,优先级高的排在前面。通过优先级情况下,构造函数入参数多的放在前面。接下里Spring就通过一套独特算法挑选出合适的构造函数(算法下一节单独介绍),然后调用bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));方法进行实例化。之后的bean实例化的流程与使用默认构造实例化bean的流程一样了。唯一不同的是constructorToUse是挑选出来的有参构造函数,argsToUse不再是null。

4.相亲算法

 3.1.2节中 for (Constructor<?> candidate : candidates){...}中挑选构造函数的算法流程在代码块中已经有了注释,但是仅仅看注释不一定能看懂Spring在干嘛。为了让我老婆也能明白Spring在干嘛,我将该算法迁移为一个大白话场景,使得人人都能明白源码的有趣之处。我将其算法命名为“相亲算法”。


每个参与过相亲或者在凌晨2、3点辗转反侧不能入眠的单身狗心里都对未来的TA在心中有杆秤,也就是一个评判标准,如果将进行数(简)学(单)建(量)(化)模以后都能向婚介机构或者亲朋好友描述自己的过滤标准。

刚大学毕业工作的小花最近就比较苦恼。周围热心的亲朋好友总是向她介绍另一半,她总忙于应付约会,但每次都不太满意。小花决定要提高相亲效率。于是根据小花自己的想法排出了一套优先级条件:

1. 首先按房产状态排序,排名顺序如下:

        1)已经购房的。

         2)有钱购房还未摇到号的。

         3)没钱或还没资格购房的。

2.信息越全,排序越高。除此之外在相同条件下,需要计算分数来分出高下

        1)年龄28岁。相差一岁扣1分。

        2)身高175cm。相差1cm扣1分。

       3) 体重65Kg。相差1KG扣1分。 

        在与小花心中白马王子形象差距越小越好。

小花最后补充:必须知道年龄、身高和体重3者中的2个条件,以此看到对方的诚意。      

根据以上标准,小花的母亲将亲戚朋友推荐的相亲对象按照以上规则进行了排序和评分。

    姓名   购房状态   年龄  身高  体重   扣分   是否符合
    老王     已购房     26  172   60    10        是
    张三     已购房     26  不详  不详      \        
    李四     摇号中     28  176   65     1        是
    赵六     摇号中     29  174   65     2        是
    田七     没钱买     30  不详  不详     \        否

按照这样的规则和评分可以看到,即使老王年龄有点大,但是在必须知道对方年龄和身高这个必要条件的前提下老王是最佳的选择。所以小花决定先找隔壁老王聊聊。

    姓名   购房状态   年龄 身高  体重   扣分   是否符合
    老王     已购房     不详 不详   60     \        
    张三     已购房     26 不详  不详      \        
    李四     摇号中     28 176   65     1        是
    赵六     摇号中     29 174   65     2        是
    田七     没钱买     30 不详  不详     \        否

如果上述老王的年龄和身高信息缺失,我们再来看看这个算法。虽然购房状态是“已购房”者的优先顺序排在前面,但是因为两人的信息不全从而失去了进入小花法眼的机会。机会留给了正在摇号中的两个人{"李四"、"赵六"},两人的资料都齐全。进入到比小分阶段,李四以1分的优势成功压倒了赵6。这中情况下,小花就要选李四了。虽然选择了李四,但是也要将不选前面的老王和张三的原因记在纸条上传给母亲大人。

    姓名   购房状态   年龄 身高  体重   扣分   是否符合
    老王     已购房     不详 不详   60     \        
    张三     已购房     26 不详  不详      \        
    李四     摇号中     28 176   64     2        是
    赵六     摇号中     29 174   65     2        是
    田七     没钱买     30 不详  不详     \        否

如果在上一个例子中李四的体重是64KG。在这种情况下李四和赵六扣的分数就一样了。这种情况下就没办法了。一方面要写纸条记录不选老王和张三的原因,而且还要暂时发一条朋友圈,记录下李四和赵六不分伯仲的情况实在是没法选择的无奈心情。

姓名   购房状态   年龄 身高  体重   扣分   是否符合
    老王     已购房     不详 不详   60     \        
    张三     已购房     26 不详  不详      \        
    李四     摇号中     28 176   64     2        是
    赵六     摇号中     29 174   65     2        是
    田七     没钱买     28 175  65     0        

如果上述例子中田七的资料是符合条件的,并且除了没钱买房,其他都挺好。扣分小于李四和赵六,那么就将田就会成为小花的交往对象。

至此,“相亲算法”介绍完了。“房产状态”三个状态依次对应的是“public”,“protected”和“private”。条件2的{年龄,身高,体重}是构造函数的入参 paramTypes.length。小花最后补充:必须知道年龄、身高和体重3者中的2个条件,minNrOfArgs=2,是构造函数必须满足的最小参数个数。表格中的分数就是typeDiffWeight。记录不选高顺位候选者原因的纸条就是LinkedList<UnsatisfiedDependencyException> causes。最后,如果出现类似李四和赵六不分伯仲的情况发朋友圈记录感慨的原型就是ambiguousConstructors集合。上述4个例子的判断逻辑就是Spring挑选构造函数的算法逻辑


bean的实例化完成,标志着bean的创建过程进行了一半。时间也就从上一节的02:40来到05:00。再坚持一下,黎明就要来了 。


5. 附录:本项目工程文件

工程目录和文件:

@Component("yadang")
public class Adam {

    private String name;

    @Autowired
    private Eve eve;

    @PostConstruct
    private void init(){
        name = "Adam";
    }

    public void sayHello(){
        System.out.println("你好,我是" + name + ". 我爱" + eve.getName());
    }

    public String getName() {
        return name;
    }
}
@Component("xiawa")
public class Eve {

    private String name;

    @Autowired
    private Adam adam;

    @PostConstruct
    private void init(){
        name = "Eve";
    }

    public void sayHello(){
        System.out.println("你好,我是" + name + ". 我爱" + adam.getName());
    }

    public String getName() {
        return name;
    }
}
@Component
@DependsOn("xiawa")
public class Human {

    private String nationality;

    public Human(@Value("China") String nationality) {
        this.nationality = nationality;
    }

    public void sayHello(){
        System.out.println("大家好,欢迎来到伊甸园");
        System.out.println("我们的国籍是:" + nationality);
    }
}
@Component()
public class AppleFactory implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return new Apple();
    }

    @Override
    public Class<?> getObjectType() {
        return Apple.class;
    }

    @Override
    public boolean isSingleton() { return false; }
}
public class Apple {
}
@Service
public class GardenofEden {

    private String gardenName;

    @Autowired
    private Adam adam;

    @Resource(name = "xiawa")
    private Eve eve;

    @Autowired
    private Human human;

    public void sayHello(){
        adam.sayHello();
        eve.sayHello();
        human.sayHello();
    }
}
@ComponentScan("com.Hodey")
public class CaseApplication {

	public static void main(String[] args) {

		AnnotationConfigApplicationContext ctx =
				new AnnotationConfigApplicationContext(CaseApplication.class);
		GardenofEden garden = ctx.getBean(GardenofEden.class);
		garden.sayHello();

		Apple apple1 = (Apple) ctx.getBean("appleFactory");
		System.out.println(apple1);

		Apple apple2 = (Apple) ctx.getBean("appleFactory");
		System.out.println(apple2);
	}
}

执行结果:

你好,我是Adam. 我爱Eve
你好,我是Eve. 我爱Adam
大家好,欢迎来到伊甸园
我们的国籍是:China
com.Hodey.learn.factory.Apple@5906ebcb
com.Hodey.learn.factory.Apple@258e2e41


 

猜你喜欢

转载自blog.csdn.net/wuyuwei/article/details/87557629