Spring IOC(五)依賴注入

Spring IOC(五)依賴注入

Spring 系列目錄(http://www.javashuo.com/article/p-kqecupyl-bm.html)html

1、autowire 五種注入方式測試

(1) 環境準備java

public class Company {
    private Department department;
    private List<Employee> employees;

    public Company() {
    }
    public Company(Department department) {
        this.department = department;
    }
    public void setDepartment(Department department) {
        this.department = department;
    }
    public void setEmployees(List<Employee> employees) {
        this.employees = employees;
    }
}

public class Employee {
    private String name;
    public void setName(String name) {
        this.name = name;
    }
}

public class Department {
    private String name;
    public void setName(String name) {
        this.name = name;
    }
}

(2) xml 配置git

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="company1" autowire="byName" class="com.github.binarylei.Company"/>
    <bean id="company2" autowire="byType" class="com.github.binarylei.Company"/>
    <bean id="company3" autowire="no" class="com.github.binarylei.Company"/>
    <bean id="company4" autowire="constructor" class="com.github.binarylei.Company">
        <constructor-arg index="0" ref="department"/>
    </bean>
    <bean id="company5" autowire="default" class="com.github.binarylei.Company"/>

    <bean id="employee1" class="com.github.binarylei.spring.Employee">
        <property name="name" value="employee1"/>
    </bean>
    <bean id="employee2" class="com.github.binarylei.spring.Employee">
        <property name="name" value="employee2"/>
    </bean>

    <bean id="department" class="com.github.binarylei.spring.Department">
        <property name="name" value="department"/>
    </bean>
</beans>

(3) 測試一把github

@Test
public void test() {
    DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(lbf);
    reader.loadBeanDefinitions(new ClassPathResource("spring-context-di.xml", getClass()));

    // 1. 名稱注入
    Company companyByName = (Company) lbf.getBean("company1");
    // 2. 類型注入,支持 List 方式注入,若是本地容器找到多個則直接拋出異常
    Company companyByType = (Company) lbf.getBean("company2");
    // 3. no
    Company companyByNo = (Company) lbf.getBean("company3");
    // 4. 構造器注入
    Company companyByConstructor = (Company) lbf.getBean("company4");
    // 5. 默認
    Company companyDefault = (Company) lbf.getBean("company5");
}

2、Spring 屬性注入源碼分析

2.1 屬性注入 - populateBean

Spring 屬性注入在 populateBean 方法中完成,有兩種注入方式:beanName 或 type 兩種。spring

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    if (bw == null) {
        if (mbd.hasPropertyValues()) {
            throw new BeanCreationException("Cannot apply property values to null instance");
        } else {
            return;
        }
    }

    // 1. 後置處理器 InstantiationAwareBeanPostProcessor,能夠先略過
    boolean continueWithPropertyPopulation = true;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                    continueWithPropertyPopulation = false;
                    break;
                }
            }
        }
    }
    if (!continueWithPropertyPopulation) {
        return;
    }

    // 2. 依賴查找。根據 beanName 或 type 查找可注入的屬性值。
    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);

    // 3. 後置處理器攔截,對屬性值進行處理 InstantiationAwareBeanPostProcessor
    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) {
            // 過濾不須要進行屬性注入的字段,如 String、BeanFactory...
            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
        }
        checkDependencies(beanName, mbd, filteredPds, pvs);
    }

    // 5. 依賴注入。至些屬性已經所有準備好了,能夠進行屬性注入。
    if (pvs != null) {
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}

上面的代碼看這很複雜,其實拋開後置處理器 InstantiationAwareBeanPostProcessor 就作了三件事,其中屬性的查找,尤爲是根據類型的查找最爲複雜:app

  1. 依賴查找。根據 beanName 或 type 查找可注入的依賴值。
  2. 依賴校驗。是否全部的字段已經所有匹配上了,根據須要是否要拋出異常
  3. 依賴注入。至些依賴已經所有準備好了,能夠進行屬性注入。

參考:源碼分析

1 . 《Spring各類依賴注入註解的區別》:https://blog.csdn.net/gaohe7091/article/details/39319363post


天天用心記錄一點點。內容也許不重要,但習慣很重要!測試

相關文章
相關標籤/搜索