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


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

Spring IOC(五)依赖注入的更多相关文章

  1. 【Spring IoC】依赖注入DI(四)

    平常的Java开发中,程序员在某个类中需要依赖其它类的方法.通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理. Spring提出了依赖注入的思想,即依赖类不由程 ...

  2. TinyFrame续篇:整合Spring IOC实现依赖注入

    上一篇主要讲解了如何搭建基于CodeFirst的ORM,并且在章节末我们获取了上下文对象的实例:BookContext.这节主要承接上一篇,来讲解如何整合Spring IOC容器实现控制反转,依赖注入 ...

  3. Spring Ioc和依赖注入

    总结一下近来几天的学习,做个笔记 以下是Spring IoC相关内容: IoC(Inversion of Control):控制反转: 其主要功能可简单概述为:将 用 new 去创建实例对象,转换为让 ...

  4. spring学习 五 依赖注入的方式

    依赖注入有两种方式: 1 构造注入,如果<bean>标签下使用<contructor-arg>,则是构造注入 2 setter注入,就是调用setter方法注入,如果<b ...

  5. Ioc容器依赖注入-Spring 源码系列(2)

    Ioc容器依赖注入-Spring 源码系列(2) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostPr ...

  6. Spring学习-理解IOC和依赖注入

    最近刚买了一本介绍ssm框架的书,里面主要对Mybatis.spring.springmvc和redis做了很多的讲解,个人觉得虽然有的内容我看不懂,但是整体上还是不错的.最近正在学习中,一边学习一边 ...

  7. SSM框架之Spring(3)IOC及依赖注入(基于注解的实现)

    Spring(3)IOC及依赖注入(基于注解的实现) 学习基于注解的 IoC 配置,大家脑海里首先得有一个认知,即注解配置和 xml 配置要实现的功能都是一样 的,都是要降低程序间的耦合.只是配置的形 ...

  8. SSM框架之Spring(2)IOC及依赖注入

    Spring(2)IOC及依赖注入 基于xml配置文件的实现 1.IOC (控制反转-Inversion Of Control) 控制反转(Inversion of Control,缩写为IoC),是 ...

  9. Spring源码之IOC容器创建、BeanDefinition加载和注册和IOC容器依赖注入

    总结 在SpringApplication#createApplicationContext()执行时创建IOC容器,默认DefaultListableBeanFactory 在AbstractApp ...

  10. Spring学习(一)——Spring中的依赖注入简介

    [前面的话] Spring对我太重要了,做个关于web相关的项目都要使用Spring,每次去看Spring相关的知识,总是感觉一知半解,没有很好的系统去学习一下,现在抽点时间学习一下Spring.不知 ...

随机推荐

  1. Physical (Raw) Versus Logical Backups

    [Physical (Raw) Versus Logical Backups] Physical backups consist of raw copies of the directories an ...

  2. 分享一个 Java String split 快速分割的方法

    java中string.split() 方法比较强大,但是split()方法采用正则表达式,速度相对会慢一点, 其实大多数场景下并不需要使用正则表达式,下面分享一个不使用正则表达式分隔字符串的方法. ...

  3. python--第四天总结

    lambda表达式 处理简单函数自动返回 学习条件运算时,对于简单的 if else 语句,可以使用三元运算来表示,即: # 普通条件语句 if 1 == 1: name = 'wupeiqi' el ...

  4. L2与L1正则化理解

    https://www.zhihu.com/question/37096933/answer/70507353 https://blog.csdn.net/red_stone1/article/det ...

  5. 测试用户体验相关——UI设计准则及方法

    之前跟我们uxc同学聊过一些,记录下来,方便在工作中不断渗透深入和理解,能够逐渐养成比较好的审美和对UI交互问题的敏锐的觉察力. 以问题为导向来吧... 第一个问题:一个menu中的图标一定要风格一致 ...

  6. PAT L3-001 凑零钱(01背包dp记录路径)

    韩梅梅喜欢满宇宙到处逛街.现在她逛到了一家火星店里,发现这家店有个特别的规矩:你可以用任何星球的硬币付钱,但是绝不找零,当然也不能欠债.韩梅梅手边有104枚来自各个星球的硬币,需要请你帮她盘算一下,是 ...

  7. Windows 64 位 mysql 5.7.20 安装教程

    mysql 5.7以上版本包解压中没有data目录和my-default.ini和my.ini文件以及服务无法启动的解决办法以及修改初始密码的方法 mysql官网下载地址:https://dev.my ...

  8. access导入报错 请求筛选模块被配置为拒绝超过请求内容长度的请求

    原因:access文件过大 解决:用压缩和修复把收缩一下access文件 报错截图如下:

  9. iOS 证书申请新步骤

    2018iOS完整的证书申请和打包过程 - 简书https://www.jianshu.com/p/2b3c2693f4f2

  10. ThinkPhp框架开发微信支付——刷卡支付

    首先讲讲我遇到的坑: 1.下载了微信的demo,界面如下,一直调试不通过,原来点击链接地址是微信测试的网页地址...要改成自己开发的网页地址.... 2.demo不是用ThinkPhp框架的,我不懂, ...