zoukankan      html  css  js  c++  java
  • Spring IoC 依赖注入(二)源码分析

    Spring IoC 依赖注入(二)源码分析

    本章主要分析 Spring IoC 依赖注入的源码,首先分析最基本的手动注入,再分析两种自动注入方式 - 名称注入和类型注入,这两种注入最核心的是如何查找依赖,Spring 中专门提供了 resolveDependency API 用于根据类型查找依赖,最后我们再回过头再看一下构造器注入和工厂方法注入。

    • 手动注入:Autowire.NO 禁止自动注入,官方推荐,也是默认的注入模式。db.propertyValues。
    • 名称注入:Autowire.BY_NAME。根据 beanName 注入,Spring 中根据名称查找 Bean 标
    • 类型注入:Autowire.BY_TYPE。根据 beanType 注入,核心是依赖查找,Spring 中提供 resolveDependency API 来查找所依赖的 Bean。
    • 依赖查找:resolveDependency(核心方法) 根据类型查找所依赖的 Bean。当然也有根据名称查找,不过代码就很简单了。
    • 构造器注入:本质还是类型注入,即通过 resolveDependency 查找依赖。
    • 工厂方法注入:基本同构造器注入。
    • AutowiredAnnotationBeanPostProcessor:@Autowired,@Value,@javax.inject.Inject 等。
    • CommonAnnotationBeanPostProcessor:@Resource,PostConstruct,@PreDestroy 等。

    1. 依赖注入口 - populateBean

    1.1 doCreateBean

    首先,我们要了解一下 Spring Bean 的整个创建过程,doCreateBean 方法主要完成了以下几件事:

    1. Bean 的实例化:Spring 常见的实例化方式有构造器实例化,工厂方法等,具体可以参考我的 Spring Bean 实例化方法总结
    2. 调用 BeanDefinition:使用后置处理器调用 Bean 的定义 BeanDefinition,这也是最后的机会修改 Bean 的定义。如 AutowiredAnnotationBeanPostProcessor 就会通过 postProcessMergedBeanDefinition 方法读取 @Autowired 等注解的信息。
    3. 提前暴露单例 Bean:用于解决循环依赖问题。
    4. 属性注入:除构造器注入或工厂方法注入外的其它注入,包括 "Setter 注入" 或 "Field 注入" 或 "方法注入" 等。
    5. 初始化:执行顺序如下:"JSR 规范 @PostConstruct" > "Spring 标准接口 InitializingBean" > "自定义方法"。详见 Spring Bean 生命周期
    6. 最后注册依赖关系:用于 Bean 销毁。
    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, 
            final @Nullable Object[] args) throws BeanCreationException {
        // 1. 实例化Bean,构造器注入或工厂方法注入
        BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
        
        // 2. 后置处理器修改Bean的定义BeanDefinition:bdp#postProcessMergedBeanDefinition
        applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
       
        // 3. 提前将Bean暴露到IoC容器中,用于解决循环依赖
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences 
                                          && isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }
        
        // 4. populateBean属性注入的核心方法,initializeBean则执行bean初始化方法
        Object exposedObject = bean;
        populateBean(beanName, mbd, instanceWrapper);
        exposedObject = initializeBean(beanName, exposedObject, mbd);
        
        // 5. 注册bean的依赖关系,用于bean销毁用
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
        return exposedObject;
    }
    

    说明: 在 Bean 的创建过程中有两个方法都可以进行依赖注入。

    • createBeanInstance :方法实例化时,构造器注入或工厂方法注入。
    • populateBean :"Setter 注入" 或 "Field 注入" 或 "方法注入" 等。

    1.2 populateBean

    下面,我们看一下 populateBean 方法是怎么进行属性注入的。populateBean 处理了 Spring 的各种依赖注入:包括自动注入(名称注入和类型注入)、注解注入(@Autowired 和 @Value 等)、手动注入等。

    1. 首先,判断是否需要进行属性注入。调用 ibp#postProcessAfterInstantiation,有时间再看一下 Spring 内部是怎么使用这个功能的,它的使用场景是什么?
    2. 自动注入:包括名称注入和类型注入。不推荐使用,只支持 XML 配置方式。
    3. 注解注入:处理 @Autowired 和 @Value 等注解,Spring 提供 ibp#postProcessProperties 可以调整 bean 实例。如 AutowiredAnnotationBeanPostProcessor 用于处理 @Autowired 和 @Value 注解。CommonAnnotationBeanPostProcessor 用于处理 @Resource 注解。
    4. 依赖检查:检查要注入的依赖是否已经完整。可以只检查简单类型(Java 原生类型、Enum、Class 等),也可以只检查对象类型。
    5. 手动注入:最基础的注入方式,实际上都委托给了 BeanWrapper 处理。
    protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
        // 1. 判断是否需要进行属性注入:ibp#postProcessAfterInstantiation
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                        return;
                    }
                }
            }
        }
    
        PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    
        // 2. 自动注入:包括名称注入和类型注入
        int resolvedAutowireMode = mbd.getResolvedAutowireMode();
        if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
            // 2.1 自动根据名称注入
            if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
                autowireByName(beanName, mbd, bw, newPvs);
            }
            // 2.2 自动根据类型注入
            if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
                autowireByType(beanName, mbd, bw, newPvs);
            }
            pvs = newPvs;
        }
    
        boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
        boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
    
        // 3. 注解注入:后置处理器ibp#postProcessProperties,大名鼎鼎的@Autowired就是在这处理的。
        PropertyDescriptor[] filteredPds = null;
        if (hasInstAwareBpps) {
            if (pvs == null) {
                pvs = mbd.getPropertyValues();
            }
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                    if (pvsToUse == null) {
                        if (filteredPds == null) {
                            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                        }
                        pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                        if (pvsToUse == null) {
                            return;
                        }
                    }
                    pvs = pvsToUse;
                }
            }
        }
        // 4. 依赖检查,循环依赖...
        if (needsDepCheck) {
            if (filteredPds == null) {
                filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            }
            checkDependencies(beanName, mbd, filteredPds, pvs);
        }
    
        // 5. 手动依赖注入
        if (pvs != null) {
            applyPropertyValues(beanName, mbd, bw, pvs);
        }
    }
    

    说明: 代码很长,但逻辑非常清晰,populateBean 方法依次处理自动注入,注解注入,手动注入。每种注入方式的代码基本上都是独立的,我们先越过自动注入和注解注入,先深入分析手动注入 applyPropertyValues 方法。

    2. 手动注入

    本小节指的手动注入是指手动指定注入字段名称,解析后添加到 bd.propertyValues 中。如

    <bean id="beanA" class="com.binarylei.spring.ioc.injection.BeanA">
        <property name="beanB" ref="beanB"/>
    </bean>
    

    2.1 相关的类说明

    在分析 applyPropertyValues 源码之前,我们先认知一下这几个类:

    1. BeanDefinition:Bean 的元信息,无论是 XML 还是注解配置,最终都会解析成 BeanDefinition,这个我们已经很熟悉了。
    2. BeanWrapper:对 Bean 操作的封装,如 JavaBean 的内省,属性的设置。其 bw.setPropertyValues(mpvs) 将属性注入到 bean 实例中。
      • BeanWrapperImpl:(默认)采用 PropertyDescriptor 进行注入,也就是 setter 方法反射注入,对应的处理器为 BeanPropertyHandler。
      • DirectFieldAccessor:采用字段注入,对应的处理器为 FieldPropertyHandler。
    3. PropertyValues:AbstractBeanDefinition 重要属性,存放手动注入的属性值,默认实现类 MutablePropertyValues。类似的 constructorArgumentValues 则是构造参数。
    4. TypeConverter:Spring 内部的类型转换器,支持两个任意对象类型之间的转换。
    5. BeanDefinitionValueResolver:将 PropertyValue 中引用类型,转换成真实对象。
    6. TypedStringValue:封装 (String, targetType),表示需要将 String 转换成指定类型 targetType。

    2.2 applyPropertyValues

    applyPropertyValues 方法的主要逻辑是遍历 bd.propertyValues 中的 PropertyValue 属性,根据引用类型提取出对象实例,再将这个对象实例转换成可以直接注入的实例。

    1. 解析对象:valueResolver.resolveValueIfNecessary(pv, originalValue) 将 pv.value 解析成实例对象。
    2. 类型转换:convertForProperty(resolvedValue, propertyName, bw, converter) 将 resolvedValue 转换成可直接进行类型注入的类型。
    3. 依赖注入: bw.setPropertyValues(mpvs) 将解析后的属性注入到 bw 实例中。Spring 属性注入(一)JavaBean 内省机制在 BeanWrapper 中的应用
    4. 结果缓存:Spring 会将 valueResolver 和 converter 解析后的最终对象缓存到 pv 中,提高效率。如果全部 pv 都不需要重新解析,则设置 mpvs.converted=true。
    protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
    
        MutablePropertyValues mpvs = null;
        List<PropertyValue> original;
    
        // 1. 获取List<PropertyValue>,如果已经解析过,则直接注入后返回
        if (pvs instanceof MutablePropertyValues) {
            mpvs = (MutablePropertyValues) pvs;
            // MutablePropertyValues已经解析,直接注入,在方法解析后会缓存已经解析的PropertyValue
            if (mpvs.isConverted()) {
                // bean注入
                bw.setPropertyValues(mpvs);
                return;
            }
            original = mpvs.getPropertyValueList();
        } else {
            original = Arrays.asList(pvs.getPropertyValues());
        }
    
        // 2. TypeConverter:用于类型转换。
        //    BeanDefinitionValueResolver:用于解析PropertyValue,如间接引用替换成直接对象
        TypeConverter converter = getCustomTypeConverter();
        if (converter == null) {
            converter = bw;
        }
        BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
    
        // 3. 逐个解析PropertyValue
        List<PropertyValue> deepCopy = new ArrayList<>(original.size());
        boolean resolveNecessary = false;
        for (PropertyValue pv : original) {
            if (pv.isConverted()) {
                // 3.1 PropertyValue已经解析
                deepCopy.add(pv);
            } else {
                String propertyName = pv.getName();
                Object originalValue = pv.getValue();
                // 3.2 标记位,实际使用resolveDependency方法查找依赖注入的对象
                if (originalValue == AutowiredPropertyMarker.INSTANCE) {
                    Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
                    if (writeMethod == null) {
                        throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
                    }
                    originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
                }
                // 3.3 提取真实的对象
                Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
                // 3.4 类型转换
                Object convertedValue = resolvedValue;
                boolean convertible = bw.isWritableProperty(propertyName) &&
                    !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
                if (convertible) {
                    convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
                }
                // 3.5 缓存解析后的PropertyValue:resolvedValue -> convertedValue
                // 3.5.1 缓存:实例没有发生变化,比如只进行属性注入等
                if (resolvedValue == originalValue) {
                    if (convertible) {
                        pv.setConvertedValue(convertedValue);
                    }
                    deepCopy.add(pv);
                // 3.5.2 缓存:TypedStringValue将String转换成指定类型targetType)
                //       TypedStringValue不需要动态转换,且不是集合或数据
                } else if (convertible && originalValue instanceof TypedStringValue &&
                         !((TypedStringValue) originalValue).isDynamic() &&
                         !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
                    pv.setConvertedValue(convertedValue);
                    deepCopy.add(pv);
                // 3.5.3 不缓存:每次都重新解析
                } else {
                    resolveNecessary = true;
                    deepCopy.add(new PropertyValue(pv, convertedValue));
                }
            }
        }
        // 4. 所有的字段都能成功解析,才会标记为转换完成,否则下次还需要动态解析
        if (mpvs != null && !resolveNecessary) {
            mpvs.setConverted();
        }
        // 5. bean依赖注入
        bw.setPropertyValues(new MutablePropertyValues(deepCopy));
    }
    

    说明: 这段代码如上所述,完成了解析对象、类型转换、结果缓存、最后进行属性注入,但这些核心功能基本上都委托给对应的类完成。applyPropertyValues 本身却很简单:

    1. 解析对象:委托 BeanDefinitionValueResolver 完成。

    2. 类型转换:委托 TypeConverter 完成。

    3. 属性注入:委托 bw 完成。

    4. 结果缓存:applyPropertyValues 方法本身完成的最大功能。我们就看一下什么情况会使用缓存?

      • 注入的字段 propertyName 必须有写方法(setter method)且注入的该字段不存在嵌套的情况(eg: person.user.name)

        boolean convertible = bw.isWritableProperty(propertyName) &&
            !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
        
      • 解析后的对象实例没有被替换(地址匹配):如动态代理等,会直接替换对象。

        resolvedValue == originalValue
        
      • 对象类型是 TypedStringValue,不需要动态转换,且不是集合或数据

        convertible && originalValue instanceof TypedStringValue &&
            !((TypedStringValue) originalValue).isDynamic() &&
            !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))
        

    2.3 BeanDefinitionValueResolver

    BeanDefinitionValueResolver#resolveValueIfNecessary(argName, value) 方法功能:解析 value 的真实类型,value 的类型不同,处理的结果也不同。本质就是进行依赖查找。

    • RuntimeBeanReference 类型:引用类型,根据 ref.beanType 或 ref.beanName 从容器中获取。
    • RuntimeBeanNameReference 类型:Spring EL 表达式解析 ref.beanName。
    • BeanDefinitionHolder 或 BeanDefinition 类型:根据 BeanDefinition 实例化 bean。
    • DependencyDescriptor:采用 beanFactory#resolveDependency 进行依赖查找。
    • ManagedList 等集合类型:规则和上述完全类似,只是返回集合而已。
    • 其它类型:如果是 String,则 Spring EL 表达式解析,其余的直接返回 originalValue。

    如 applyPropertyValues 中的 AutowiredPropertyMarker.INSTANCE 类型:表示使用 beanFactory#resolveDependency 进行依赖查找。BeanDefinitionBuilder 添加属性时就会使用时这些类型。

    public BeanDefinitionBuilder addPropertyValue(String name, @Nullable Object value) {
        this.beanDefinition.getPropertyValues().add(name, value);
        return this;
    }
    public BeanDefinitionBuilder addPropertyReference(String name, String beanName) {
        this.beanDefinition.getPropertyValues().add(name, new RuntimeBeanReference(beanName));
        return this;
    }
    public BeanDefinitionBuilder addAutowiredProperty(String name) {
        this.beanDefinition.getPropertyValues().add(name, AutowiredPropertyMarker.INSTANCE);
        return this;
    }
    

    2.4 依赖检查

    依赖注入过程中,populateBean 调用 applyPropertyValues 方法进行属性注入之前,还有一步是依赖检查,默认是关闭的。在 AbstractBeanDefinition 中定义了如下 4 种检查方案,默认为 DEPENDENCY_CHECK_NONE。

    public static final int DEPENDENCY_CHECK_NONE = 0;
    public static final int DEPENDENCY_CHECK_OBJECTS = 1;
    public static final int DEPENDENCY_CHECK_SIMPLE = 2;
    public static final int DEPENDENCY_CHECK_ALL = 3;
    

    依赖检查 checkDependencies 方法,检查的 Bean 中 setter 方法对应的字段是否都是 value 值注入,如果字段没有 setter 则不用检查,又分为简单类型和对象类型检查。

    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
    if (needsDepCheck) {
        if (filteredPds == null) {
            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
        }
        checkDependencies(beanName, mbd, filteredPds, pvs);
    }
    

    说明: populateBean 先调用 filterPropertyDescriptorsForDependencyCheck 过滤出需要进行依赖检查的字段,默认只要字段有 setter 方法,除开基本类型或特殊的类型,都要进行校验。checkDependencies 则判断 pvs 中是否包含 pd.getName(),如果不包含则根据检查级别抛出异常。

    依赖检查因为默认是关闭的,而且代码也很简单,就不多说了。而且开发中好像也没有使用过这个功能。

    2. 自动注入

    Spring 提供了三种自动注入的手段:名称注入、类型注入、构造器注入。其中构造器注入本质是类型注入。

    • 名称注入:调用 beanFactory#getBean(beanName) 方法查找依赖。无法注入时抛出异常。
    • 类型注入:调用 beanFactory#resolveDependency 方法查找依赖。无法注入时不会抛出异常。
    • 构造器注入:同类型注入。

    无论是名称注入还是类型注入,都是通过依赖查找,通过 pvs.add(propertyName, propertyValue) 将属性添加到 bd.pvs 中,然后统一调用 bw.setPropertyValues(pvs) 将属性注入到 bean 中。

    2.1 那些字段会自动注入

    unsatisfiedNonSimpleProperties 方法定义了 bean 中那些字段需要自动注入。正常情况下,只要定义了 setter 方法的字段都会自动注入。

    1. JavaBean 中字段有写方法,即 setter 方法。
    2. 不需要进行依赖检查的字段。指定类型 ignoredDependencyTypes 或指定接口 ignoredDependencyInterfaces 中的方法不需要进行类型检查 。
    3. 没有进行指定属性值的字段。
    4. 简单类型及其对应的数组类型:如 Java 原生类型、包装类型、Class、Enum、Number 等基础类型。具体参考 BeanUtils#isSimpleValueType 方法。
    protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
        Set<String> result = new TreeSet<>();
        PropertyValues pvs = mbd.getPropertyValues();
        PropertyDescriptor[] pds = bw.getPropertyDescriptors();
        for (PropertyDescriptor pd : pds) {
            if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
                !BeanUtils.isSimpleProperty(pd.getPropertyType())) {
                result.add(pd.getName());
            }
        }
        return StringUtils.toStringArray(result);
    }
    

    下面看一下那些方法不需要进行依赖检查。

    protected boolean isExcludedFromDependencyCheck(PropertyDescriptor pd) {
        return (AutowireUtils.isExcludedFromDependencyCheck(pd) ||
                this.ignoredDependencyTypes.contains(pd.getPropertyType()) ||
                AutowireUtils.isSetterDefinedInInterface(pd, this.ignoredDependencyInterfaces));
    }
    

    说明: 有三种情况:一是写方法不存在;二是字段类型为指定不需要检查的类型 ignoredDependencyTypes;三是在指定接口中的方法也不需要进行类型检查 ignoredDependencyInterfaces。Spring 没有默认的 ignoredDependencyTypes 类型,但指定默认的接口 ignoredDependencyInterfaces 如下,这些 Aware 接口都是通过接口回调进行注入:

    // AbstractAutowireCapableBeanFactory
    ignoreDependencyInterface(BeanNameAware.class);
    ignoreDependencyInterface(BeanFactoryAware.class);
    ignoreDependencyInterface(BeanClassLoaderAware.class);
    
    // AbstractApplicationContext#prepareBeanFactory
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
    

    2.2 名称注入

    当注入模式为 AUTOWIRE_BY_NAME,采用依赖注入,目前只支持 XML 配置。

    <bean id="beanA" class="com.binarylei.spring.ioc.injection.BeanA" autowire="byName"/>
    

    autowireByName 的代码也很简单。

    protected void autowireByName(String beanName, AbstractBeanDefinition mbd, 
                                  BeanWrapper bw, MutablePropertyValues pvs) {
        String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
        for (String propertyName : propertyNames) {
            if (containsBean(propertyName)) {
                Object bean = getBean(propertyName);
                pvs.add(propertyName, bean);
                registerDependentBean(propertyName, beanName);
            }
        }
    }
    

    说明: 根据 getBean(propertyName) 查找依赖。

    2.3 类型注入

    protected void autowireByType(
        String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
    
        TypeConverter converter = getCustomTypeConverter();
        if (converter == null) {
            converter = bw;
        }
    
        Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
        String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
        for (String propertyName : propertyNames) {
            PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
            if (Object.class != pd.getPropertyType()) {
                MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
                // eager 类型 @Lazy 属性,是否提前初始化
                boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
                // DependencyDescriptor 封装了字段注入的详细信息
                DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
                // (核心)依赖查找最核心的API
                Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
                if (autowiredArgument != null) {
                    pvs.add(propertyName, autowiredArgument);
                }
                // 注册依赖关系,用于 bean 销毁
                for (String autowiredBeanName : autowiredBeanNames) {
                    registerDependentBean(autowiredBeanName, beanName);
                }
                autowiredBeanNames.clear();
            }
        }
    }
    

    说明: 调用 beanFactory#resolveDependency 方法查找依赖。重点还要说明一点的是

    • AutowireByTypeDependencyDescriptor:封装了依赖注入点的详细信息,可以是字段 Field,也可以是方法参数 MethodParameter。
    • eager:作用类型 @Lazy,是否提前初始化。

    每天用心记录一点点。内容也许不重要,但习惯很重要!

  • 相关阅读:
    C#序列化效率对比
    将聚合记录集逆时针和顺时针旋转90度(行列互换)
    Sql的行列转换
    log4net配置
    input框添加阴影效果
    WCF自定义地址路由映射(不用svc文件)
    Jquery对当前日期的操作(格式化当前日期)
    用JQuery获取输入框中的光标位置
    sublime text3安装后html:5+Tab不能快速生成html头部信息的解决办法
    js获取url传递参数,js获取url?号后面的参数
  • 原文地址:https://www.cnblogs.com/binarylei/p/12337137.html
Copyright © 2011-2022 走看看