springboot啟動流程(九)ioc依賴注入


所有文章

https://www.cnblogs.com/lay2017/p/11478237.html

 

正文

在前面的幾篇文章中,我們多次提到這么一個轉化過程:

Bean配置 --> BeanDefinition --> Bean對象

Bean的配置可以是xml配置,也可以是java配置。BeanDefinition配置在內存中數據對象,也是Bean的元數據。在springboot啟動過程當中,refresh上下文這個步驟將會解析xml配置以及java配置,從而把Bean的配置解析成為BeanDefinition。我們也可以將這個過程簡稱為Bean的元數據生成。

這里我們需要注意!refresh只是把BeanDefinition注冊到BeanFactory中,而不是把Bean注冊到BeanFactory中。(這里我們不討論non-lazy-init=true的情況)

而是在我們調用上下文的getBean的時候才會去根據BeanDefinition生成

@Override
public Object getBean(String name) throws BeansException {
    //
    return getBeanFactory().getBean(name);
}

上下文的getBean方法把功能實現委托給了BeanFactory,跟進AbstractBeanFactory的getBean方法

@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}

 

doGetBean獲取Bean的邏輯

跟進doGetBean方法

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

    final String beanName = transformedBeanName(name);
    Object bean;

    // 如果拿到已經注冊的單例Bean,直接返回結果
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        //
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    } else {

        //

        try {
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

            //

            // 創建單例
            if (mbd.isSingleton()) {
                // 回調創建
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        return createBean(beanName, mbd, args);
                    } catch (BeansException ex) {
                        //
                    }
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            } else if (mbd.isPrototype()) {
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    // 每次創建
                    prototypeInstance = createBean(beanName, mbd, args);
                } finally {
                    //
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            } else {
                //
            }
        } catch (BeansException ex) {
            //
        }
    }
    //

    return (T) bean;
}

該方法的邏輯是先去單例的緩存中找,如果找得到直接返回。如果找不到,那么判斷是單例還是原型,如果是單例創建並緩存,如果是原型那么每次都創建新的。

 

getSingleton獲取單例

跟進創建單例的時候的getSingleton方法

private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    // 內置鎖控制
    synchronized (this.singletonObjects) {
        // 雙重校驗
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            //

            boolean newSingleton = false;
            //
            try {
                // 回調創建Bean
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            catch (IllegalStateException ex) {
                //
            }
            catch (BeanCreationException ex) {
                //
            } finally {
                //
            }
            if (newSingleton) {
                // 添加單例到緩存中
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}

這里采用雙重校驗機制控制了單例,如果二次校驗的時候發現緩存中沒有Bean,那么就會回調創建的方法去創建一個Bean,然后再注冊到本地堆緩存當中。

 

createBean創建Bean

我們先回到調用getSingleton的方法位置,看一下回調方法實什么

if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, () -> {
        try {
            return createBean(beanName, mbd, args);
        } catch (BeansException ex) {
            //
        }
    });
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

創建實現委托給了createBean方法,該方法的實現屬於AbstractAutowireCapableBeanFactory,跟進該類的CreateBean方法

@Override
protected Object createBean(
        String beanName, 
        RootBeanDefinition mbd, 
        @Nullable Object[] args) throws BeanCreationException {
    //
    RootBeanDefinition mbdToUse = mbd;

    //

    try {
        // 創建Bean實例
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        //
        return beanInstance;
    } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
        //
    } catch (Throwable ex) {
        //
    }
}

 

繼續跟進doCreateBean

protected Object doCreateBean(
        final String beanName, 
        final RootBeanDefinition mbd, 
        final @Nullable Object[] args) throws BeanCreationException {

    // 創建Bean實例對象
    BeanWrapper instanceWrapper = null;
    //
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    //
    try {
        // 自動注入
        populateBean(beanName, mbd, instanceWrapper);
        //
    } catch (Throwable ex) {
        //
    }
    //

    return exposedObject;
}

該方法主要包含兩個步驟,創建Bean的實例對象和自動注入

 

createBeanInstance創建實例

跟進createBeanInstance

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // 省略

    // 默認使用無參數構造方法獲取實例
    return instantiateBean(beanName, mbd);
}

跟進instantiateBean方法

private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
    try {
        Object beanInstance;
        final BeanFactory parent = this;
        if (System.getSecurityManager() != null) {
            beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
                    // 實例化
                    getInstantiationStrategy().instantiate(mbd, beanName, parent),
                    getAccessControlContext());
        } else {
            // 實例化
            beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
        }
        BeanWrapper bw = new BeanWrapperImpl(beanInstance);
        initBeanWrapper(bw);
        return bw;
    } catch (Throwable ex) {
        //
    }
}

// 獲取實例化策略
protected InstantiationStrategy getInstantiationStrategy() {
    return this.instantiationStrategy;
}

默認的實例化策略是CglibSubclassingInstantiationStrategy,它又繼承自SimpleInstantiationStrategy,跟進SimpleInstantiationStrategy類的instantiate方法

public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
    // 如果不存在需要被重寫的方法,那么就不需要使用cglib重寫並覆蓋該類
    if (!bd.hasMethodOverrides()) {
        Constructor<?> constructorToUse;
        synchronized (bd.constructorArgumentLock) {
            //
        }
        // 通過構造方法實例化
        return BeanUtils.instantiateClass(constructorToUse);
    } else {
        // 需要通過cglib生成
        return instantiateWithMethodInjection(bd, beanName, owner);
    }
}

到這里,BeanDefinition就被初步創建成為了一個Bean實例對象。

 

populateBean自動注入

前面我們說到,doCreateBean有兩個步驟

1)創建Bean實例對象

2)自動注入

回顧一下doCreateBean的代碼

protected Object doCreateBean(
        final String beanName, 
        final RootBeanDefinition mbd, 
        final @Nullable Object[] args) throws BeanCreationException {

    // 創建Bean實例對象
    BeanWrapper instanceWrapper = null;
    //
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    //
    try {
        // 自動注入
        populateBean(beanName, mbd, instanceWrapper);
        //
    } catch (Throwable ex) {
        //
    }
    //

    return exposedObject;
}

接下來,我們跟進populateBean方法看看當前這個創建好的Bean實例實怎么注入其它Bean的

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    // 

    // 獲取待注入的property,配置文件中配置的<property>將在這里被處理
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

    // 按照名字或者類型獲取屬性,這里會進行遞歸
    if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
        // 按照名字獲取屬性
        if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }
        // 按照類型獲取屬性
        if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }
        pvs = newPvs;
    }

    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

    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);
                    }
                    // 后置處理器處理@Autowired @Resource等注解
                    pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                    if (pvsToUse == null) {
                        return;
                    }
                }
                pvs = pvsToUse;
            }
        }
    }
    // 注入<property>屬性
    if (pvs != null) {
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}

我們看到populateBean主要做兩件事,獲取屬性值,然后把屬性值給注入到Bean里面去。我們重點關注后置處理器處理@Autowired @Resource注解的邏輯。

 

AutowiredAnnotationBeanPostProcessor處理@Autowired注入注解

跟進AutowiredAnnotationBeanPostProcessor類的postProcessPropertyValues方法

public PropertyValues postProcessPropertyValues(
        PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {

    return postProcessProperties(pvs, bean, beanName);
}

跟進postProcessProperties方法

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    // 獲取當前Bean的元數據,將包含@Autowired等注解的標注的待注入元素
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    try {
        // 注入元素
        metadata.inject(bean, beanName, pvs);
    }
    catch (BeanCreationException ex) {
        throw ex;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
    }
    return pvs;
}

后置處理屬性值包含兩件事,找到當前Bean被@Autowired等注解標注的待注入的元素,然后注入相應的到元素。

跟進findAutowiringMetadata方法

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
.
    String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());

    InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
    if (InjectionMetadata.needsRefresh(metadata, clazz)) {
        synchronized (this.injectionMetadataCache) {
            metadata = this.injectionMetadataCache.get(cacheKey);
            if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                if (metadata != null) {
                    metadata.clear(pvs);
                }
                // 構造元數據
                metadata = buildAutowiringMetadata(clazz);
                this.injectionMetadataCache.put(cacheKey, metadata);
            }
        }
    }
    return metadata;
}

繼續跟進buildAutowiringMetadata

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
    List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
    Class<?> targetClass = clazz;

    do {
        final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

        ReflectionUtils.doWithLocalFields(targetClass, field -> {
            // 找到注解@Autowired
            AnnotationAttributes ann = findAutowiredAnnotation(field);
            if (ann != null) {
                // 
                boolean required = determineRequiredStatus(ann);
                currElements.add(new AutowiredFieldElement(field, required));
            }
        });

        //

        elements.addAll(0, currElements);
        // 往父類遞歸
        targetClass = targetClass.getSuperclass();
    }
    while (targetClass != null && targetClass != Object.class);

    return new InjectionMetadata(clazz, elements);
}

這里找到注解@Autowired的Field以后包裝成Element,然后向父類遞歸,最后包裝成元數據

 

我們回到postProcessProperties方法以后,再跟進inject注入方法看看

protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
        throws Throwable {

    if (this.isField) {
        Field field = (Field) this.member;
        ReflectionUtils.makeAccessible(field);
        // 反射設置值,這里的取值會對依賴進行遞歸處理
        field.set(target, getResourceToInject(target, requestingBeanName));
    } else {
        // 省略
    }
}

這里主要是對Bean的Field的一個反射來設置值,值的獲取將會進行遞歸處理

 

CommonAnnotationBeanPostProcessor處理@Resource注入注解

觸發后置處理器的邏輯跟AutowiredAnnotationBeanPostProcessor是一樣的,我們直接來看看CommonAnnotationBeanPostProcessor的buildAutowiringMetadata方法

private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
    List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
    Class<?> targetClass = clazz;

    do {
        final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

        ReflectionUtils.doWithLocalFields(targetClass, field -> {
            if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
                //
            }
            else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
                //
            }
            // 如果注解了@Resource
            else if (field.isAnnotationPresent(Resource.class)) {
                //
                if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
                    // 添加element
                    currElements.add(new ResourceElement(field, field, null));
                }
            }
        });

        //

        elements.addAll(0, currElements);
        // 向父類遞歸
        targetClass = targetClass.getSuperclass();
    }
    while (targetClass != null && targetClass != Object.class);

    return new InjectionMetadata(clazz, elements);
}

元數據返回以后的流程和@Autowired也是一樣的。

 

總結

本文粗略地過了一下ioc依賴注入的過程,從BeanDefinition --> Bean的過程。我們一開始創建了Bean的實例,然后再通過遞歸解析依賴注入處理把Bean之間的關系結合處理。在最后還提了一下@Autowired和@Resource的后置處理器。

依賴注入的過程相對來說還是很復雜的,包含了非常多的細節處理。但是我們可以簡單地去概括一下它,整個依賴注入的過程就是創建Bean,並建立Bean之間的關系。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM