项目实训 10 学习Spring(4)

326 阅读6分钟

1.4.3:使用依赖:(depend-on)

如果一个 bean 是另一个 bean 的依赖项,则通常意味着将一个 bean 设置为另一个 bean 的属性。通常,您可以使用基于 XML 的配置元数据中的 element完成此操作。但是,有时 bean 之间的依赖性不太直接。(即仅有依赖性但并不为相互的引用)。depends-on属性可以在初始化使用此元素的 bean 之前显式强制初始化一个或多个 bean。

要表示对多个 bean 的依赖性,请提供一个 bean 名称列表作为depends-on属性的值(逗号,空格和分号是有效的分隔符):

image.png

1.4.4:懒初始化bean:

默认情况下,作为初始化的一部分,Application Context将会创建和配置所有的单例范围的bean(即只创建一次的bean)。如果不想这样,通过bean定义标记为延迟初始化防止单例bean的预实例化。延迟初始化的 bean 告诉 IoC 容器在首次请求时而不是在启动时创建一个 bean 实例。

在 XML 中,此行为由元素上的lazy-init属性或元素上的default-lazy-init属性控制,如以下示例所示:

image.png

image.png

但是,当延迟初始化的 bean 是未延迟初始化的单例 bean 的依赖项时,ApplicationContext将在启动时创建延迟初始化的 bean,因为它必须满足单例的依赖关系。延迟初始化的 bean 被注入到其他未延迟初始化的单例 bean 中。

1.4.5:自动布线合作者:

Spring 容器可以自动装配协作 bean 之间的关系。

自动装配的优点:

自动装配能大大减少指定属性或构造函数参数的需要;

       随着对象的发展(例如添加了个属性为其他类的对象),自动装配可以自动更新配置。

使用基于 XML 的配置元数据时,可以使用元素的autowire属性为 bean 定义指定自动装配模式。您可以为每个 bean 指定自动装配,因此可以选择要自动装配的装配。下表描述了四种自动装配模式:

image.png

自动装配的局限性和缺点:

  1. property和constructor-arg设置中的显式依赖项始终会覆盖自动装配。

  2. 自动装配不如显式接线精确。

  3. 接线信息可能不适用于可能从 Spring 容器生成文档的工具。

  4. 容器内的多个 bean 定义可能与要自动装配的 setter 方法或构造函数参数指定的类型匹配。对于数组,集合或Map实例,这不一定是问题。但是,对于需要单个值的依赖项,不会任意解决此歧义。如果没有唯一的 bean 定义可用,则引发异常。

对于4选择:

  1. 放弃自动布线,转而使用明确的布线。

  2. 通过将其元素的primary属性设置为true,将单个 bean 定义指定为主要候选对象。

  3. 通过基于注解的配置实现更细粒度的控件。

  4. 通过将其autowire-candidate属性设置为false来避免自动装配 bean 的类型。

从自动装配中排除bean:

在每个 bean 的基础上,您可以从自动装配中排除一个 bean。使用 Spring 的 XML 格式,将元素的autowire-candidate属性设置为false。容器使特定的 bean 定义对于自动装配基础结构不可用。autowire-candidate属性旨在仅影响基于类型的自动装配。它不会影响按名称显示的显式引用。如果名称匹配,按名称自动装配仍会注入 Bean。

您还可以基于与 Bean 名称的模式匹配来限制自动装配候选。顶级元素在其default-autowire-candidates属性内接受一个或多个模式。例如,要将自动装配候选状态限制为名称以Repository结尾的任何 bean,请提供值*Repository。要提供多种模式,请在以逗号分隔的列表中定义它们。 Bean 定义的autowire-candidate属性的true或false的显式值始终优先。对于此类 bean,模式匹配规则不适用。

这些技术对于您不希望通过自动装配将其注入其他 bean 的 bean 非常有用。这并不意味着排除的 bean 本身不能使用自动装配进行配置。

1.4.6:方法注入:

当单例 Bean 需要与另一个单例 Bean 协作或非单例 Bean 需要与另一个非单例 Bean 协作时,通常可以通过将一个 Bean 定义为另一个 Bean 的属性来处理依赖性。故当 bean 的生命周期不同时会出现问题。假设单例 bean A 需要使用非单例(原型)bean B,也许在 A 的每个方法调用上都使用。容器仅创建一次单例 bean A,因此只有一次机会来设置属性。

一个解决方案是放弃某些控制反转。您可以通过实现ApplicationContextAware接口来使 bean A 知道容器,并在每次 bean A 需要beanB时对容器进行 getBean(“ B”)调用询问(通常是新的)bean B 实例。以下示例显示了此方法:

image.png

查找方法注入(Lookup method inject):

​ 上面的代码是每次都从applicationContext重新获取一个新实例来实现的。Spring提供了一个Lookup method inject机制,它可以改变方法的返回值,来达到方法注入的效果。对应的有annotation和xml两种使用方式。

annotation的使用方式@Lookup,把@Lookup加到你要改变方法返回值的方法上:

image.png Loopup的注释中的写明了需要返回的bean名字,如果没有写bean name,那么会根据createCommand的函数返回值类型去查找对应的bean

​ Spring的Lookup method inject实现原理的是使用CGLIB动态生成一个类去继承CommandManager,重写createCommand方法。然后根据@Lookup中指定的bean Name或者createCommand方法的返回类型判断需要返回的bean。createCommand可以是abstract和可以不是。因为使用的是继承,所以CommandManager类和createCommand方法都不能是final的。

image.png

对应实现的XML配置:

image.png

任意方法替换(Arbitrary method replacement):

​ Lookup method inject只是改变了方法的返回值,但是method replacement可以替换bean 容器里任意方法的实现,达到方法的完全注入,一般情况下不要这个使用特性!

此特性,只能基于XML配置实现。

假如我们要替换如下类的computeValue方法:

image.png

第一步,我们要现实org.springframework.beans.factory.support.MethodReplacer接口:

image.png

第二步,在XML中,使用replaced-method元素进行配置.:

image.png

在上面的xml中,在元素replaced-method中使用了arg-type。它的作用是在有多个方法重载时,根据arg-type中指定的参数class名字来确定具体替换哪一个方法。