springIOC源码解析(四)

这两天工作比较闲,上午的时候我又仔细看了一遍spring初始化bean加载流程,下面我挑重点写一下我的收获

  • spring如何保持bean的单例
    对于singleton的bean而言,spring在初始化bean之后,会把beanName及bean实例保存到一个map中(DefaultSingletonBeanRegistry中的singletonObjects);当再次要获取bean实例时直接从map中拿;而prototype的bean每次都从新创建一个
    这里衍生出一个问题,这里的单例和单例模式中的单例是什么关系?我的理解是:单例模式中的单例,是通过设计方式让其自身成为单例,与容器无关.用单例模式创建的单例类,一般是工具类,不会让容器来管理;spring中的单例则是对于容器来说,也就是说,在spring的管理下,bean在容器中是保持单例,而其自身不是单例

  • spring如何管理有依赖关系的bean

    spring在创建bean实例之后,会用BeanWrapper对bean进行包装,BeanWrapper的主要功能之一就是为bean提供属性编辑器PropertyEditor,通过属性编辑器对属性进行赋值,主要代码如下

public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue,
            Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException {
        ......
        Object convertedValue = newValue;
        ......
        if (requiredType != null) {
            // Try to apply some standard type conversion rules if appropriate.

            if (convertedValue != null) {
                if (Object.class == requiredType) {
                    return (T) convertedValue;
                }
                else if (requiredType.isArray()) {
                    // Array required -> apply appropriate conversion of elements.
                    if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
                        convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
                    }
                    return (T) convertToTypedArray(convertedValue, propertyName, requiredType.getComponentType());
                }
                else if (convertedValue instanceof Collection) {
                    // Convert elements to target type, if determined.
                    convertedValue = convertToTypedCollection(
                            (Collection<?>) convertedValue, propertyName, requiredType, typeDescriptor);
                    standardConversion = true;
                }
                else if (convertedValue instanceof Map) {
                    // Convert keys and values to respective target type, if determined.
                    convertedValue = convertToTypedMap(
                            (Map<?, ?>) convertedValue, propertyName, requiredType, typeDescriptor);
                    standardConversion = true;
                }
                if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {
                    convertedValue = Array.get(convertedValue, 0);
                    standardConversion = true;
                }
                if (String.class == requiredType && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
                    // We can stringify any primitive value...
                    return (T) convertedValue.toString();
                }
                else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
                    if (conversionAttemptEx == null && !requiredType.isInterface() && !requiredType.isEnum()) {
                        try {
                            Constructor<T> strCtor = requiredType.getConstructor(String.class);
                            return BeanUtils.instantiateClass(strCtor, convertedValue);
                        }
                        catch (NoSuchMethodException ex) {
                            // proceed with field lookup
                            if (logger.isTraceEnabled()) {
                                logger.trace("No String constructor found on type [" + requiredType.getName() + "]", ex);
                            }
                        }
                        catch (Exception ex) {
                            if (logger.isDebugEnabled()) {
                                logger.debug("Construction via String failed for type [" + requiredType.getName() + "]", ex);
                            }
                        }
                    }
                    String trimmedValue = ((String) convertedValue).trim();
                    if (requiredType.isEnum() && "".equals(trimmedValue)) {
                        // It's an empty enum identifier: reset the enum value to null.
                        return null;
                    }
                    convertedValue = attemptToConvertStringToEnum(requiredType, trimmedValue, convertedValue);
                    standardConversion = true;
                }
                else if (convertedValue instanceof Number && Number.class.isAssignableFrom(requiredType)) {
                    convertedValue = NumberUtils.convertNumberToTargetClass(
                            (Number) convertedValue, (Class<Number>) requiredType);
                    standardConversion = true;
                }
            }
            else {
                // convertedValue == null
                if (javaUtilOptionalEmpty != null && requiredType == javaUtilOptionalEmpty.getClass()) {
                    convertedValue = javaUtilOptionalEmpty;
                }
            }
            ......

        return (T) convertedValue;
    }
  • bean延迟加载问题
    大家都知道设置lazy-init=”true”可以设置bean在需要的时候实例化(lazy-init默认false).但这里可能存在一个很容易忽略的细节,只有使用ApplicationContext的时候设置lazy-init才有能控制bean实例化的时机(是容器启动时还是需要使用时);如果使用BeanFactory bean只会在调getBean方法时(也就是需要使用时)进行实例化

OK,下一张我们分析通过ApplicationContext启动容器的过程

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值