项目实训 8 学习Spring(2)

197 阅读9分钟

1.3:Bean总览:

image.png

Bean行为配置元素:Scope(决定何时创建bean)   

Bean要来新创建的对象中设置其他的配置设置:即属性赋值。

Bean中的定义:class、name、scope、constructor arguments、property、autowiring mode、延迟初始化模型、Initialization method、destruction method。

除了包含有关如何创建特定 bean 的信息的 bean 定义之外,ApplicationContext实现还允许注册在容器外部(由用户)创建的现有对象。这是通过getBeanFactory()方法访问 ApplicationContext 的 BeanFactory 来完成的,该方法返回 BeanFactory 的DefaultListableBeanFactory的实现。 DefaultListableBeanFactory通过registerSingleton(..)和registerBeanDefinition(..)方法支持此注册。

Bean 元数据和手动提供的单例实例需要尽早注册,以便容器在自动装配和其他自省步骤中正确地推理它们。

1.3.1:命名bean:

每个 bean 具有一个或多个标识符。这些标识符在承载 Bean 的容器内必须唯一。一个 bean 通常只有一个标识符。但是,如果需要多个,则可以将多余的视为别名。

在基于 XML 的配置元数据中,您可以使用id属性和name属性,或同时使用这两者来指定 bean 标识符。 id属性可让您精确指定一个 ID。如果要为 bean 引入其他别名,还可以在name属性中指定它们,并用逗号(,),分号(;)或空格分隔。

Bean 命名约定:约定是在命名 bean 时将标准 Java 约定用于实例字段名称。也就是说,bean 名称以小写字母开头,并从那里用驼峰式大小写。

通过在 Classpath 中进行组件扫描,Spring 会按照前面描述的规则为未命名的组件生成 Bean 名称:从本质上讲,采用简单的类名称并将其初始字符转换为小写。但是,在(不寻常的)特殊情况下,如果有多个字符并且第一个和第二个字符均为大写字母,则会保留原始大小写。

在 bean 定义本身中,可以使用id属性指定的最多一个名称和name属性中任意数量的其他名称的组合来为 bean 提供多个名称。

在实际定义 bean 的地方指定所有别名并不总是足够的。有时需要为在别处定义的 bean 引入别名。在大型系统中通常是这种情况,在大型系统中,配置在每个子系统之间分配,每个子系统都有自己的对象定义集。在基于 XML 的配置元数据中,您可以使用元素来完成此操作。

image.png

1.3.2:实例化bean:

Bean 定义实质上是创建一个或多个对象的方法。当被询问时,容器将查看命名 bean 的配方,并使用该 bean 定义封装的配置元数据来创建(或获取)实际对象。

如果使用基于 XML 的配置元数据,则可以在元素的class属性中指定要实例化的对象的类型(或类)。

容器可以通过以下两种方式之一使用Class属性:

  1. 通常,在容器本身通过反射性地调用其无参构造函数直接创建 Bean对象,这在某种程度上等效于new运算符的 Java 代码。

  2. 指定包含被调用以创建对象的static工厂方法的实际类,在不太常见的情况下,容器将在类上调用static工厂方法以创建 Bean。从static工厂方法的调用返回的对象类型可以是同一类,也可以是完全不同的另一类。

内部类名称:

image.png

用构造函数实例化:

当通过构造方法创建一个 bean 时,所有普通类都可以被 Spring 使用并与之兼容。也就是说,正在开发的类不需要实现任何特定的接口或以特定的方式进行编码。只需指定 bean 类就足够了。但是,需要一个默认(空)构造函数。

使用静态工厂方法实例化:

定义使用静态工厂方法创建的 bean 时,请使用class属性来指定包含static工厂方法的类,并使用名为factory-method的属性来指定工厂方法本身的名称。

例:

image.png

使用实例工厂方法实例化:

使用实例工厂方法实例化从容器中调用现有 bean 的非静态方法以创建新 bean。

将class属性留空,并在factory-bean属性中,在当前(或父容器或祖先容器)中指定包含要创建该对象的实例方法的 bean 的名称。使用factory-method属性设置工厂方法本身的名称。

例:

image.png

一个工厂类也可以包含一个以上的工厂方法。例:

image.png

这种方法表明,工厂 Bean 本身可以通过依赖项注入(DI)进行管理和配置。

1.4:Dependencies:

典型的企业应用程序不包含单个对象(或 Spring 术语中的 bean)。即使是最简单的应用程序,也有一些对象可以协同工作,以呈现最终用户视为一致的应用程序。

1.4.1:依赖注入:

 依赖注入(DI)是一个过程,通过该过程,对象只能通过构造函数参数,工厂方法的参数或在构造或创建对象实例后在对象实例上设置的属性来定义其依赖关系。从工厂方法返回。然后,容器在创建 bean 时注入那些依赖项。

基于构造函数的依赖关系注入:

基于构造函数的 DI 是通过容器调用具有多个参数(每个参数代表一个依赖项)的构造函数来完成的。调用带有特定参数的static工厂方法来构造 Bean 几乎是等效的。

以下示例显示了只能通过构造函数注入进行依赖项注入的类:

image.png

构造函数参数解析匹配通过使用参数的类型进行。如果 Bean 定义的构造函数参数中不存在潜在的歧义(参数之间无继承关系),则在实例化 Bean 时,直接将参数传递给构造函数。

例:

image.png

假设ThingTwo和ThingThree类没有通过继承关联,则不存在潜在的歧义。因此,

image.png

当参数使用简单类型时,Spring无法确定值的类型(因为无法创建bean),因此需要使用type属性显示指定构造函数参数的类型,则容器就可以使用简单类型的类型匹配。

 

image.png

image.png

还可以可以使用index属性来显式指定构造函数参数的索引:(索引从0开始)

image.png

除了解决多个简单值的歧义性之外,指定索引还可以解决歧义。

还可以使用构造函数参数名称来消除歧义:

image.png

要立即使用该功能,必须在启用调试标志的情况下编译代码,以便 Spring 可以从构造函数中查找参数名称。如果您不能或不想使用 debug 标志编译代码,则可以使用@ConstructorProperties JDK注解 显式命名构造函数参数。

image.png

基于Setter的依赖项注入:

基于setter的 DI 是通过在调用无参数构造函数或无参数static工厂方法以实例化您的 bean 之后,在您的 bean 上调用 setter 方法来完成的。(标签)

下面的示例显示只能通过使用纯 setter 注入来依赖注入的类:

image.png

基于构造函数vs基于setter的DI:

由于可以混合使用基于构造函数的 DI 和基于 setter 的 DI,因此将构造函数用于强制性依赖项并将 setter 方法或配置方法用于可选依赖性是一个很好的经验法则。请注意,在 setter 方法上使用@Required注解可用于使属性成为必需的依赖项。

Spring 团队通常提倡构造函数注入,因为它可以让您将应用程序组件实现为不可变对象,并确保所需的依赖项不是null。

Setter 注入主要应仅用于可以在类中分配合理的默认值的可选依赖项。否则,必须在代码使用依赖项的任何地方执行非空检查。 setter 注入的一个好处是,setter 方法使该类的对象在以后可以重新配置或重新注入。

依赖关系解决流程:

1.Application Context用描述所有bean的配置元数据创建和初始化。可通过XML,Java代码或注解来指定配置元数据。

2.对于每个bean,其依赖项都是他的属性,构造函数参数或静态工厂方法的参数。创建bean时会将这些依赖项提供给bean。

3.每个属性或构造函数参数都是要设置的值,需要实际定义或者是对容器中另一个bean的引用。

  1. 作为值的每个属性或构造函数参数都将从其指定的格式转换为该属性或构造函数参数的实际类型。默认情况下,Spring 可以将以字符串格式提供的值转换为所有内置类型,例如int,long,String,boolean等等。

在创建容器时,Spring 容器会验证每个 bean 的配置。在实际创建 Bean 之前,不会设置 Bean 属性。创建容器时,将具有单例作用域并设置为预先实例化(默认)的 Bean先进行创建。其范围在Bean Scopes中定义。否则,仅在请求时才创建该Bean。

循环依赖问题:

如果主要使用构造函数注入,则可能会创建无法解决的循环依赖方案。例如:A 类通过构造函数注入需要 B 类的实例,而 B 类通过构造函数注入需要 A 类的实例。如果为将类 A 和 B 相互注入而配置了 bean,则 Spring IoC 容器会在运行时检测到此循环引用,并抛出BeanCurrentlyInCreationException。

解决方法:修改些源代码或避免使用构造函数注入,而仅使用setter注入。

       因为setter注入,例beanA和beanB,spring可以先将beanB带有beanA=null属性的对象传给beanA,接着beanA再注入beanB补充了beanB中的null属性。

如果不存在循环依赖关系,则在将一个或多个协作 Bean 注入从属 Bean 时,每个协作 Bean 都将被完全配置,然后再注入到从属 Bean 中。这意味着,如果 bean A 依赖于 bean B,则 Spring IoC 容器会在对 bean A 调用 setter 方法之前完全配置 beanB。

依赖项注入示例:

基于setter注入:

image.png

image.png

基于构造函数注入:\

image.png

image.png

调用static工厂方法以返回对象的实例:

image.png

image.png

factory 方法返回的类的类型不必与包含static factory 方法的类的类型相同(尽管在此示例中为)。实例(非静态)工厂方法可以以基本上相同的方式使用(除了使用factory-bean属性而不是class属性)。