DoGetBean流程

DoGetBean流程

在这里插入图片描述
主流程大致为,从缓存中找到是否已经实例化了该 singleton bean,如果已经实例化好了,那么就直接返回;如果在缓存中没有找到,则将当前的 bean 封装为 RootBeanDefinition,然后通过调用 DefaultSingletonBeanRegistry#getSingleton 得到初始化好的 singleton bean,然后将其注册至缓存( step 1.3.3 addSingleton ),然后再判断是普通 bean 还是 factory bean 作必要的处理( step 1.4 getObjectForBeanInstance )后,最后返回;

AbstractAutowireCapableBeanFactory

AbstractAutowireCapableBeanFactory#doCreateBean 方法是初始化 bean 的最核心的入口方法,执行流程如 Do Get Bean 流程所示,

主流程主要做了这么三件事情,一、instantiate bean;二、populate bean;三、initialize bean;

包含五个子流程,他们分别是 factory instantiate bean、autwire instantiate bean、default instantiate bean、populate bean 以及 initialize bean,其中,前三个子流程对应第一件事情,实例化 bean;其次的子流程 populate bean 对应的是第二件事情,为 bean 设置 property 参数;最后一个子流程 [initialize bean] 对应最后一件事情既初始化 bean,这里的初始化指的是是对创建好的 bean 做一些修饰动作的。

第一件事情:instantiate bean

该步骤对应 Do Get Bean 流程中的 createBeanInstance;根据 bean 的不同配置方式,实现了三种实例化 bean 的方式,分别是 factory instantiate bean、autwire instantiate bean 以及 default instantiate bean;

factory instantiate bean
用工厂方法实例化 bean,待叙;

autwire instantiate bean
通过 autowire 注解的方式实例化 bean,待叙;

default instantiate bean
此步骤对应 Do Get Bean 流程中的 Step 1.3.1.1.3.1.3 instantiateBean,其对应子流程 default instantiate bean

第二件事情:populate bean

调用 AbstractAutowireCapableBeanFactory#populateBean 正式给 bean 的参数进行赋值
赋值的主流程主要包括两个部分,resolve property value object 和 set property value to bean

resolve property value

对应上面 Sequence Diagram 中的 Step 1.5 - Step 1.7;这一步主要是去遍历当前 bean 所有的 property,并依次解析(resolve)得到对应的 Java 对象;通过方法 BeanDefinitionValueResolver#resolveValueIfNecessary 进行解析,解析的过程是针对不同类型的 Property,采用不同的解析方式,里面目前总共对应了十种类型,先看看它的源码

public Object resolveValueIfNecessary(Object argName, Object value) {
    // We must check each value to see whether it requires a runtime reference
    // to another bean to be resolved.
    if (value instanceof RuntimeBeanReference) { // 这里表示该 bean definition ref 引用的是一个 bean,那么这里,必须对该 bean 进行初始化操作;
        RuntimeBeanReference ref = (RuntimeBeanReference) value;
        return resolveReference(argName, ref);
    }
    else if (value instanceof RuntimeBeanNameReference) {
        String refName = ((RuntimeBeanNameReference) value).getBeanName();
        refName = String.valueOf(doEvaluate(refName));
        if (!this.beanFactory.containsBean(refName)) {
            throw new BeanDefinitionStoreException(
                    "Invalid bean name '" + refName + "' in bean reference for " + argName);
        }
        return refName;
    }
    else if (value instanceof BeanDefinitionHolder) {
        // Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.
        BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
        return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
    }
    else if (value instanceof BeanDefinition) {
        // Resolve plain BeanDefinition, without contained name: use dummy name.
        BeanDefinition bd = (BeanDefinition) value;
        String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
                ObjectUtils.getIdentityHexString(bd);
        return resolveInnerBean(argName, innerBeanName, bd);
    }
    else if (value instanceof ManagedArray) {
        // May need to resolve contained runtime references.
        ManagedArray array = (ManagedArray) value;
        Class<?> elementType = array.resolvedElementType;
        if (elementType == null) {
            String elementTypeName = array.getElementTypeName();
            if (StringUtils.hasText(elementTypeName)) {
                try {
                    elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader());
                    array.resolvedElementType = elementType;
                }
                catch (Throwable ex) {
                    // Improve the message by showing the context.
                    throw new BeanCreationException(
                            this.beanDefinition.getResourceDescription(), this.beanName,
                            "Error resolving array type for " + argName, ex);
                }
            }
            else {
                elementType = Object.class;
            }
        }
        return resolveManagedArray(argName, (List<?>) value, elementType);
    }
    else if (value instanceof ManagedList) {
        // May need to resolve contained runtime references.
        return resolveManagedList(argName, (List<?>) value);
    }
    else if (value instanceof ManagedSet) {
        // May need to resolve contained runtime references.
        return resolveManagedSet(argName, (Set<?>) value);
    }
    else if (value instanceof ManagedMap) {
        // May need to resolve contained runtime references.
        return resolveManagedMap(argName, (Map<?, ?>) value);
    }
    else if (value instanceof ManagedProperties) {
        Properties original = (Properties) value;
        Properties copy = new Properties();
        for (Map.Entry<Object, Object> propEntry : original.entrySet()) {
            Object propKey = propEntry.getKey();
            Object propValue = propEntry.getValue();
            if (propKey instanceof TypedStringValue) {
                propKey = evaluate((TypedStringValue) propKey);
            }
            if (propValue instanceof TypedStringValue) {
                propValue = evaluate((TypedStringValue) propValue);
            }
            copy.put(propKey, propValue);
        }
        return copy;
    }
    else if (value instanceof TypedStringValue) {
        // Convert value to target type here.
        TypedStringValue typedStringValue = (TypedStringValue) value;
        Object valueObject = evaluate(typedStringValue);
        try {
            Class<?> resolvedTargetType = resolveTargetType(typedStringValue);
            if (resolvedTargetType != null) {
                return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);
            }
            else {
                return valueObject;
            }
        }
        catch (Throwable ex) {
            // Improve the message by showing the context.
            throw new BeanCreationException(
                    this.beanDefinition.getResourceDescription(), this.beanName,
                    "Error converting typed String value for " + argName, ex);
        }
    }
    else {
        return evaluate(value);
    }
}

RuntimeBeanReference 类型解析
对应需要被解析的配置为john的 property spouse,它所对应的值是另一个 bean jane;既是一个去解析一个ref bean。
通过调用this.beanFactory.getBean(refName)再次进入Do Get Bean 流程初始化得到该 ref bean;
TypedStringValue 类型解析
这里主要被解析的 Property value 的类型配置为

其 Property value 的值在配置文件中就是一个纯的字符串类型;但从源码中可以知道,Property value 是可以包含 value type 的,所以,在解析 TypedStringValue 的时候,需要根据 value type 进行解析;具体逻辑参考resolveTargetType(typedStringValue);方法。 **set property value to bean** 此步骤的主流程主要是通过Java Method 反射将解析出来的值赋值给当前的 bean;对应时序图中的 Step 1.8 setPropertyValues

可以看到,通过遍历 deepCopy ArrayList 对象中已经解析过后的 PropertyValue,最终由 BeanWrapperImpl 对象通过方法的反射,将值注入给当前的 bean,Step 1.8.1.2.1.2.2 writeMethod.invoke

@Override
public void setValue(final Object object, Object valueToApply) throws Exception{
    final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
            ((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() :
            this.pd.getWriteMethod());
    if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers()) && !writeMethod.isAccessible()) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                @Override
                public Object run() {
                    writeMethod.setAccessible(true);
                    return null;
                }
            });
        }
        else {
            writeMethod.setAccessible(true);
        }
    }
    ....
    writeMethod.invoke(getWrappedInstance(), valueToApply);
    
    ....
}

第三件事情:initialize bean

其实就是对已经创建好的 bean instance 进行”修饰”的过程
主要方法为

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
  
    invokeAwareMethods(beanName, bean); // 调用实现了 *Aware 接口的方法,比如注入 ApplicationContext... 
    

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        // 调用 bean-post-processor 的 before initialization 回调方法
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); 
    }

    try {
        invokeInitMethods(beanName, wrappedBean, mbd); // 调用 InitializingBean#afterPropertiesSet 回调 
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }

    if (mbd == null || !mbd.isSynthetic()) {
        // 调用 bean-post-processor 的 after initialization 回调方法
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); 
    }

    return wrappedBean; // 这里的 wrapped bean 指的是被 bean-post-processor 修饰以后的包装 bean
}

整个过程可以理解为三大块,

  • 注入 Aware 对象
  • 回调 bean-post-processors 接口方法
  • 回调 InitializingBean 接口方法
    注入 Aware 对象
    允许实现了该 Aware 接口的当前 bean 能够有机会通过回调的方式注入 Spring 容器中默认实现了 Aware 接口的 bean,比如 BeanFactory 等;看看源码,
private void invokeAwareMethods(final String beanName, final Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof BeanNameAware) {
            ((BeanNameAware) bean).setBeanName(beanName);
        }
        if (bean instanceof BeanClassLoaderAware) {
            ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
        }
        if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
        }
    }
}

要注入ApplicaitonContext对象,bean 必须实现ApplicatonContextAware接口;
回调 bean-post-processors 接口方法
Object postProcessBeforeInitialization(Object bean, String beanName)
从方法的注释中不难发现,该方法是在回调 InitializeBean 接口方法之前调用,并且是在 populate bean) 之后进行的调用,通常是对原有 bean 做一层封装,然后返回该封装对象;这就是我在前文所描述的,其实就是是对原有 bean 起到修饰的作用;

Object postProcessAfterInitialization(Object bean, String beanName)
从方法的注释中不难发现,该方法是在回调 InitializeBean 接口方法之前调用,同样也是在 populate bean) 之后进行的调用
回调 InitializingBean 接口方法

protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
        throws Throwable {

    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        if (logger.isDebugEnabled()) {
            logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
        }
        .....
        ((InitializingBean) bean).afterPropertiesSet();
        .....
    }

    if (mbd != null) {
        String initMethodName = mbd.getInitMethodName();
        if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                !mbd.isExternallyManagedInitMethod(initMethodName)) {
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}

可以看到,主要回调的是InitializingBean接口的afterPropertiesSet方法,所以,我们可以让某个 bean 实现 InitializingBean 接口,并通过该接口实现一些当 bean 实例化好以后的回调方法

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值