spring-framework-reference(5.1.1.RELEASE)中文版——Core部分 (7)

请记住,要使这一工作开箱即用,您的代码必须在启用调试标志的情况下进行编译,以便Spring可以从构造函数查找参数名。如果不能或不想使用调试标志编译代码,可以使用@ConstructorProperties JDK注释显式地为构造函数参数命名。然后示例类必须如下所示:

package examples; public class ExampleBean { // Fields omitted @ConstructorProperties({"years", "ultimateAnswer"}) public ExampleBean(int years, String ultimateAnswer) { this.years = years; this.ultimateAnswer = ultimateAnswer; } } Setter-based Dependency Injection

在调用无参数构造函数或无参数静态工厂方法实例化bean之后,容器调用bean上的setter方法就可以实现基于setter的DI。

下面的示例显示了一个只能通过使用纯setter注入进行依赖注入的类。这个类是常规Java。它是一个POJO,不依赖于容器特定的接口、基类或注释。

public class SimpleMovieLister { // the SimpleMovieLister has a dependency on the MovieFinder private MovieFinder movieFinder; // a setter method so that the Spring container can inject a MovieFinder public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } // business logic that actually uses the injected MovieFinder is omitted... }

ApplicationContext为其管理的bean支持基于构造函数和基于setter的DI。在通过构造函数方法注入一些依赖项之后,它还支持基于setter的DI。
您可以以BeanDefinition的形式配置依赖关系,并将其与PropertyEditor实例一起使用,以将属性从一种格式转换为另一种格式。然而,大多数Spring用户并不直接使用这些类(即通过编程方式),而是使用XML bean定义、带注释的组件(即用@Component、@Controller等注释的类)或基于java的@Configuration类中的@Bean方法。然后,这些源在内部转换为BeanDefinition实例,并用于加载整个Spring IoC容器实例。

Constructor-based or setter-based DI?

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

Spring团队通常提倡构造函数注入,因为它允许您将应用程序组件实现为不可变对象,并确保所需的依赖项不为空。此外,构造注入的组件总是以完全初始化的状态返回给客户端(调用)代码。作为补充说明,大量的构造函数参数是一种糟糕的代码味道,这意味着类可能有太多的职责,应该重构,以便更好地处理关注点的适当分离。

Setter注入主要应该只用于可选的依赖项,这些依赖项可以在类中分配合理的默认值。否则,在代码使用依赖项的任何地方都必须执行非空检查。setter注入的一个好处是,setter方法使该类的对象可以稍后重新配置或重新注入。因此,通过JMX MBean进行管理是setter注入的一个引人注目的用例。

用对特定类最有意义的DI样式。有时候,在处理没有源代码的第三方类时,会为您做出选择。例如,如果第三方类不公开任何setter方法,那么构造函数注入可能是惟一可用的DI形式。

Dependency Resolution Process

容器执行以下bean依赖项解析:

使用描述所有bean的配置元数据创建和初始化ApplicationContext。配置元数据可以由XML、Java代码或注释指定。

对于每个bean,其依赖关系以属性、构造函数参数或静态工厂方法参数的形式表示(如果使用静态工厂方法而不是普通构造函数)。这些依赖项在bean实际创建时提供给bean。

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

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

在创建容器时,Spring容器验证每个bean的配置。然而,直到真正创建bean时,才会设置bean属性本身。当创建容器时,将创建单实例作用域并设置为预实例化的bean(默认)。作用域在Bean作用域中定义。否则,只有在请求bean时才会创建它。创建bean可能会导致创建bean的图,因为创建和分配了bean的依赖项及其依赖项(等等)。请注意,这些依赖项之间的解析不匹配可能出现得较晚——即在第一次创建受影响的bean时。

如果使用主构造函数注入,则可以创建不可解析的循环依赖场景。

Circular dependencies

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzdjpw.html