Spring IOC(五)依赖注入

Spring IOC(五)依赖注入

Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html)

一、autowire 五种注入方式测试

(1) 环境准备

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 配置

<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) 测试一把

@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");
}

二、Spring 属性注入源码分析

2.1 属性注入 - populateBean

Spring 属性注入在 populateBean 方法中完成,有两种注入方式:beanName 或 type 两种。

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 就做了三件事,其中属性的查找,尤其是根据类型的查找最为复杂:

  1. 依赖查找。根据 beanName 或 type 查找可注入的依赖值。
  2. 依赖校验。是否所有的字段已经全部匹配上了,根据需要是否要抛出异常
  3. 依赖注入。至些依赖已经全部准备好了,可以进行属性注入。

参考:

1 . 《Spring各种依赖注入注解的区别》:https://blog.csdn.net/gaohe7091/article/details/39319363


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

posted on 2019-01-30 22:40  binarylei  阅读(471)  评论(0编辑  收藏  举报

导航