专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

Spring IoC 源码阅读

Spring IOC 总览

121_1.png  最近这几个月的时间一直在看 Spring的源码,学习的过程本身就是一个输入输出,反复循环的过程,经过这一段时间的学习,从以前只是使用的阶段到现在 Spring的理解又有了一些新的认识。通过之后的文章来记录学习的过程。

  在开始 Spring IoC 之前,先来了解一下 控制反转依赖倒置的设计思想。

  控制反转,是指依赖对象的获得反转,也就是说这是一个解耦的过程。对象之间的依赖关系管理由具体对象来完成,会导致代码之间的耦合程度增强。因此对象之间的依赖关系,交由一个地方统管理(Ioc 容器)。

  依赖倒置,控制反转将对象之间依赖关系的管理权交了出去,对象不需要自己维护依赖关系,而是通过 IoC 容器来完成。从对象的角度来说,依赖对象的获取从自己主动区创建,变成从容器中去获取。

  控制反转的实现有很多种方式。经常会听到依赖查找依赖注入。在Spring中,IoC容器是实现这个模式的载体,依赖注入是主要的实现方式。所谓依赖注入,即组件之间的依赖关系由容器在应用系统运行期来决定,也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。在对象生成或者初始化的时候将数据注入到对象中(完成数据的注入),也可以通过将依赖对象的引用注入到对象的数据域中(通过对象的引用完成方法的调用)。

Spring 实现IoC 的思路和方法

 IoC 统一集中处理对象之间的依赖关系。Spring实现IOC的思路是提供一些配置信息用来描述类之间的依赖关系,然后有容器去解析这些配置信息,继而维护对象之间的依赖关系,前提是对象之间的依赖关系必须在类中定义好。

方法:

1、 应用程序中提供类,提供依赖关系(属性或者构造方法)
2、 把需要交给容器管理的对象通过配置信息告诉容器(xml,annotation、javaconfig)
3、 把各个类之间的依赖关系通过配置信息告诉容器

Spring IoC 设计

  Ioc被理解为一个容器,在Spring中提供了一系列功能不同的容器,它们有不同的实现,完成不同的功能。当然Spring中也提供的最基础容器,为IoC容器设定了最基本的功能规范。下面通过IoC接口设计图来一探究竟。

BeanFactory接口设计路径.jpg

121_2.png  上述图片中标注出两条BeanFactory接口的设计路径,一条是蓝色线条表示,一条红色线条表示。

  • 从接口 BeanFactoryHierarchicalBeanFactory,再到 ConfigurableBeanFactory,是一条 BeanFactory 设计路径。在 BeanFactory 中定义了最基本的 IoC 容器的功能,包含有 getBean() IoC 中最基础的方法; 在 HierarchicalBeanFactory 中继承了 BeanFactory 接口,并增加了 getParentBeanFactory()的接口功能,使 BeanFactory 具备了双亲 IoC 容器的管理功能;在 ConfigurableBeanFactory 接口中,定义了一些 BeanFactory的配置功能,比如 setParentBeanFactory() 设置双亲IoC容器,通过 addBeanPostProcessor() 配置 Bean 后置处理器,等等。
  • BeanFactoryListableBeanFactory,再到 ApplicationContext。这条路径是另一条主要的设计路径。ListableBeanFactoryHierarchicalBeanFactory 两个接口连接 BeanFactory 接口定义和 ApplicationContext 应用上线文的接口定义。在 ListableBeanFactory 中 细化了许多 BeanFactory 的功能,如 getBeanDefinitionNames() 接口方法;HierarchicalBeanFactory 如上所述。

从上图中可以看到 BeanFactory是 IoC 容器的最基本的实现,是所有 IoC 容器实现的基类,其中规范的 IoC 容器 最基本的功能。 反观 ApplicationContext 是 IoC 容器的一种接口,是 BeanFactory 的子接口,但是他继承了 ResourcePatternResolverEnvironmentCapableMessageSourceApplicationEventPublisher 接口,在 BeanFactory 的基础上添加一些功能,使得容器可以支持一些更高级的特性。

依赖注入的方式

  • 接口注入
  • setter注入
>     setter注入也称设值注入,IoC容器通过成员变量的setter方法来注入被依赖的对象。这种注入方式
>     简单、直观,因而在Spring的依赖注入中大量使用。
>     
  • 构造器注入
>     通过构造器来完成成员变量的注入,就是驱动Spring在底层以反射的方式执行带指定参数的构造器,当执行带
>     参数的构造器时,就可以利用构造器参数对成员变量执行初始化。
>     

Spring Framework 中,仅使用构造函数setter 注入。下面先对这两张注入方式做一个简单的比较。

构造函数注入 setter 注入
没有部分注入 有部分注入
不会覆盖 setter 属性 会覆盖 setter 属性
任意修改都会创建一个新实例 任意修改不会创建一个新实例
适用于设置很多属性 适用于设置少量属性

   BeanFactorySpring IoC 中最基础的类,在BeanFactory中提供了最基本的IoC容器的功能,定义了IoC容器最基本的形式,并且提供了IoC 容器所应该遵循的最基本的原则。在Spring中,BeanFactory只是一个接口类,对IoC的基本功能做了封装。其实现 类,如DefaultListableBeanFactoryXmlBeanFactoryApplicationContext等都可以看成是IoC容器附加某种功能的具体实现。接下来从源码的角度看看,在这个接口类中都做了什么:

public interface BeanFactory {

    /**
     * 使用转义符"&"来得到 FactoryBean本身。用来区分通过容器获取 FactoryBean 产生的对象,和 FactoryBean 本身
     * 举例:
     *   myObject  得到一个 FactoryBean (产生)修饰的对象
     *   &myObject 得到的是 FactoryBean 的工厂,用来产生 FactoryBean 的对象
     * 区分 FactoryBean 和 BeanFactory
     *   FactoryBean 是对象,是一个能产生或者修饰对象生成的工厂 Bean
     *   BeanFactory 是对象工厂 也是就 IOC 容器,所有的 Bean 都是由 BeanFactory 进行管理
     */
    String FACTORY_BEAN_PREFIX = "&";

    /**
     * 通过指定的名字获取Bean
     */
    Object getBean(String name) throws BeansException;

    /**
     * 通过Bean的名称 和 类型 获取 Bean
     */
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;

    /**
     * 通过Bean的名称 和 构造参数 获取 Bean
     */
    Object getBean(String name, Object... args) throws BeansException;

    /**
     * 通过Bean的类型
     */
    <T> T getBean(Class<T> requiredType) throws BeansException;

    /**
     * 通过Bean的类型 和 构造参数
     */
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

    /**
     * 方法用于获取指定bean的提供者,可以看到它返回的是一个ObjectProvider,其父级接口是ObjectFactory
     */
    <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);

    /**
     * 通过ResolvableType获取ObjectProvider
     */
    <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

    /**
     * 通过指定的名字判断 工厂中是否定义 或者 已经注册了 一个 BeanDefinition
     */
    boolean containsBean(String name);

    /**
     * 用来出查询指定名字的 bean 是否是单例(singleton)的,单例属性 是在 BeanDefinition 指定的
     */
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

    /**
     * 用来出查询指定名字的 bean 是否是原型(prototype)的,原型属性 是在 BeanDefinition 指定的
     */
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

    /**
     * 判断指定名字的 Bean 的 Class 类型是否是特定的 Class 类型
     */
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

    /**
     * 判断指定名字的 Bean 的 Class 类型是否是特定的 Class 类型
     */
    boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

    /**
     * 查询指定名字的 Bean 的 Class 类型
     */
    @Nullable
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;

    /**
     * 获取指定的名字的 Bean 的所有别名,别名是用户在 BeanDefinition 中自己定义的
     */
    String[] getAliases(String name);

}

  BeanFactory接口设计了getBean() 方法,这个方法是IoC容器API的主要方法,通过这个方法, 可以取得IoC容器中管理的BeanBean的取得是通过指定的名字来索引的。如果需要在获取Bean的时候对Bean的类型 进行检查,BeanFactory接口定义了带有参数的getBean()方法,这个方法的使用与不带参数的方式类似,不同的是增加了对Bean检索的类型的要求。


个人微信公众号:

121_3.png个人github: github.com/FunCheney

文章永久链接:https://tech.souyunku.com/28095

未经允许不得转载:搜云库技术团队 » Spring IoC 源码阅读

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们