Spring5源码分析(三):依赖注入源码

寵の児 提交于 2020-03-11 01:48:36

写在前面

        在分析Spring依赖注入的过程之前,建议您先了解:Spring IOC 源码解析,这样或许会让你的思路更加清晰。

1.依赖注入介绍

        依赖注入,即 Spring 中的 DI(Dependency Injection)

        在我们学习 Spring 的使用时,我们最熟悉它的特点是:IOC 控制反转DI 依赖注入。Spring 通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

        书面介绍:依赖注入,就是指对象是被动的接受依赖类而不是自己主动去寻找。也就是说对象不是从IOC容器中查找它的依赖类,而是在容器实例化对象的时候,已经将该对象所依赖的类注入给了该对象。

2.何时进行依赖注入

       当 Spring IOC 容器启动时完成定位加载注册操作,此时 IOC容器已经获取到 applicationContext.xml 配置文件中的全部配置,并以 BeanDefinition类的形式保存在一个名为:beanDefinitionMap 的 ConcurrentHashMap 中。如下所示:

//存储注册信息的BeanDefinition
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

        此时 IOC容器只是对这些 BeanDefinition 类进行存储,而并没有真正的创建实例对象,也就是说并没有进行依赖注入操作。那么何时完成依赖注入操作??

        何时依赖注入,此处就涉及到了 lazy-init 属性的使用。lazy-init 属性是 Spring 中用来延迟加载 bean 的。使用在用户定义的标签中,默认为false。使用实例如下:

//lazy-init默认为 false,可省略
<bean id="testBean" class="com.eacxzm.TestBean">
 
//lazy-init为 true时
<bean id="testBean" class="com.eacxzm.TestBean" lazy-init="true">

依赖注入,分如下两种情况:lazy-init 属性为 true / false 时

       ① lazy-init 属性默认为 false。这种情况会在启动 Spring 容器时,完成实例对象的创建。即 Spring 容器启动时触发依赖注入。

       ②当用户为<bean>标签手工配置 lazy-init=true属性后,这样容器在启动时并不会完成实例对象的创建,不会触发依赖注入。只有当用户第一次通过调用 Spring 的 getBean()方法时,才会向 IOC 容器索要 Bean 对象,此时 IOC 容器才会触发依赖注入。

3.源码分析从何入手

       我们在学习 Spring 的使用时,都是通过如下一段代码,开启 Spring 的学习之路。通过本文以上介绍,依赖注入源码分析,就是从 getBean() 方法入手。

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
User user = (User)applicationContext.getBean("user");

       Spring IOC 源码解析,我们知道 BeanFactory 接口定义了 Spring IOC 容器的基本功能规范,是Spring最底层的接口。BeanFactory 接口中重载了几个 getBean( )方法。getBean() 方法的具体实现,是由 AbstractBeanFactory 类来实现的,所以我们从 AbstractBeanFactory 类中的 getBean() 方法入手。此处附 BeanFactory接口一览

public interface BeanFactory {
 
    //对 FactoryBean 的转义定义,因为如果使用 bean 的名字检索 FactoryBean 得到的对象是工厂生成的对象,如果需要得到工厂本身,需要转义
    String FACTORY_BEAN_PREFIX = "&";
 
    //根据 bean 的名字,获取在 IOC 容器中得到 bean 实例
    Object getBean(String name) throws BeansException;
 
    //根据 bean 的名字和 Class 类型来得到 bean 实例,增加了类型安全验证机制。
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;
 
    //根据 Class 类型来获取bean实例
    <T> T getBean(Class<T> requiredType) throws BeansException;
 
    //根据 bean 的名字和指定参数,来获取bean实例
    Object getBean(String name, Object... args) throws BeansException;

	//省略部分代码    
}

4.源码时序图

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!