Spring里的容器和Bean对象

"控制反转"是指new实例工作不由程序员来做而是交给Spring容器来做。在Spring中BeanFactory是IOC容器的实际代表者。

Spring 容器是 Spring 框架的核心。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。这些对象被称为 Spring Beans.

通过阅读配置元数据提供的指令,容器知道对哪些对象进行实例化,配置和组装。配置元数据可以通过 XML,Java 注释或 Java 代码来表示。

Spring里的容器和Bean对象

Spring IoC 容器利用 Java 的 POJO(plain old Java object) 类和配置元数据来生成完全配置和可执行的系统或应用程序。

Spring的两种容器实现:

(1) Spring BeanFactory 容器:最简单的容器,给 DI 提供了基本的支持,它用 org.springframework.beans.factory.BeanFactory 接口来定义。BeanFactory 或者相关的接口,如 BeanFactoryAware,InitializingBean,DisposableBean等
(2) Spring ApplicationContext 容器:该容器添加了更多的企业特定的功能,例如从一个属性文件中解析文本信息的能力,发布应用程序事件给感兴趣的事件监听器的能力。该容器是由 org.springframework.context.ApplicationContext 接口定义。

在我测试的Spring 5.0.2中,BeanFactory已经被标注为Deprecated了:

Spring里的容器和Bean对象

ApplicationContext 包含 BeanFactory 所有的功能,一般情况下,相对于 BeanFactory,ApplicationContext 会更加优秀。当然,BeanFactory 仍可以在轻量级应用中使用,比如移动设备或者基于 applet 的应用程序。

最常被使用的 ApplicationContext 接口实现:

  • ClassPathXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,不需要提供 XML 文件的完整路径,只需正确配置 CLASSPATH 环境变量即可,因为容器会从 CLASSPATH 中搜索 bean 配置文件。
  • FileSystemXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,需要提供给构造器 XML 文件的完整路径。

看个FileSystemXmlApplicationContext的例子:

Spring里的容器和Bean对象

输出:

Spring里的容器和Bean对象

Bean对象

被称作 bean 的对象是构成应用程序的支柱也是由 Spring IoC 容器管理的。bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。这些 bean 是由用容器提供的配置元数据创建的。

Spring IoC 容器完全由实际编写的配置元数据的格式解耦。有三种方法把配置元数据提供给 Spring 容器:

(1) 基于 XML 的配置文件
(2) 基于注解的配置
(3) 基于 Java 的配置

Bean的作用域

  • singleton:在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,默认值
  • prototype: 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()
  • request: 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
  • session:同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境
  • global-session:一般用于Portlet应用环境,该运用域仅适用于WebApplicationContext环境

singleton

Singleton是默认的作用域,也就是说,当定义 Bean 时,如果没有指定作用域配置项,则 Bean 的作用域被默认为 singleton.

看个例子:

Spring里的容器和Bean对象

无论用context API获取多少次作用域为singleton的Bean对象,Spring IOC容器中只会存在一个Bean对象的实例。

Bean对象的实例什么时候创建的?

从调用栈能看出,是在Spring IOC容器创建时进行Bean实例的创建。

Spring里的容器和Bean对象

把scope改成prototype再试:

Spring里的容器和Bean对象

这次,scope为prototype的Bean对象一共实例化了两次,因为两次构造函数被调用了:

Spring里的容器和Bean对象

从调试器的调用栈能发现,prototype作用域的Bean对象,实例化发生延迟至其真正被请求时。

要获取更多Jerry的原创文章,请关注公众号"汪子熙":
Spring里的容器和Bean对象