本章内容:
声明bean
构造器注入和Setter方法注入
装配bean
控制bean的创建和销毁
但是大多数电影(总之,都还是很优秀的)都是由成千上万的人一起协作来完成的,他们有着共同的目标:制作一部广受欢迎的佳作。
在这方面,一个优秀的软件与之相比并没有太大区别。任何一个成功的应用都是由多个为了实现某一个业务目标而相互协作的组件构成的。这些组件必须彼此了解,并且相互协作来完成工作。
但是,正如我们在第1章中所看到的,创建应用对象之间关联关系的传统方法(通过构造器或者查找)通常会导致结构复杂的代码,这些代码很难被复用也很难进行单元测试。如果情况不严重的话,这些对象所做的事情只是超出了它应该做的范围;而最坏的情况则是,这些对象彼此之间高度耦合,难以复用和测试。
在Spring中,对象无需自己查找或创建与其所关联的其他对象。相反,容器负责把需要相互协作的对象引用赋予各个对象。
例如,一个订单管理组件需要信用卡认证组件,但它不需要自己创建信用卡认证组件。订单管理组件只需要表明自己两手空空,容器就会主动赋予它一个信用卡认证组件。
创建应用对象之间协作关系的行为通常称为装配(wiring),这也是依赖注入(DI)的本质。在本章我们将介绍使用Spring装配 bean的基础知识。因为DI是Spring的最基本要素,所以在开发基于Spring的应用时,你随时都在使用这些技术。
在Spring中装配bean有多种方式。作为本章的开始,我们先花一点时间来介绍一下配置Spring容器最常见的三种方法。
2.1 Spring配置的可选方案
如第1章中所述,Spring容器负责创建应用程序中的bean并通过DI来协调这些对象之间的关系。但是,作为开发人员,你需要告诉Spring要创建哪些bean并且如何将其装配在一起。
当描述bean如何进行装配时,Spring具有非常大的灵活性,它提供了三种主要的装配机制:
1.在XML中进行显式配置。(最后用它)
2.在Java中进行显式配置。(其次用它)
3.隐式的bean发现机制和自动装配。 (仅可以都用它)
Spring有多种可选方案来配置bean,这是非常棒的,但有时候你必须要在其中做出选择。这方面,并没有唯一的正确答案。你所做出的选择必须要适合你和你的项目。而且,谁说我们只能选择其中的一种方案呢?Spring的配置风格是可以互相搭配的,所以你可以选择使用XML装配一些bean,使用Spring基于Java的配置(JavaConfig)来装配另一些bean,而将剩余的bean让Spring去自动发现。
即便如此,我的建议是尽可能地使用自动配置的机制。显式配置越少越好。当你必须要显式配置bean的时候(比如,有些源码不是由你来维护的,而当你需要为这些代码配置bean的时候),我推荐使用类型安全并且比XML更加强大的JavaConfig。---->最后,只有当你想要使用便利的XML命名空间,并且在JavaConfig中没有同样的实现时,才应该使用XML。
在本章中,我们会详细介绍这三种技术并且在整本书中都会用到它们。现在,我们会尝试一下每种方法,对它们是什么样子的有一个直观的印象。作为Spring配置的开始,我们先看一下Spring的自动化配置。
2.2 自动化装配bean
在本章稍后的内容中,你会看到如何借助Java和XML来进行Spring装配。尽管你会发现这些显式装配技术非常有用,但是在便利性方面,最强大的还是Spring的自动化配置。如果Spring能够进行自动化装配的话,那何苦还要显式地将这些bean装配在一起呢?
Spring从两个角度来实现自动化装配:
组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean。
自动装配(autowiring):Spring自动满足bean之间的依赖。
组件扫描和自动装配组合在一起就能发挥出强大的威力,它们能够将你的显式配置降低到最少。
为了阐述组件扫描和装配,我们需要创建几个bean,它们代表了一个音响系统中的组件。首先,要创建CompactDisc类,Spring会发现它并将其创建为一个bean。然后,会创建一个CDPlayer类,让Spring发现它,并将CompactDisc bean注入进来。
2.2.1 创建可被发现的bean
CD为我们阐述DI如何运行提供了一个很好的样例。如果你不将CD插入(注入)到CD播放器中,那么CD播放器其实是没有太大用处的。所以,可以这样说,CD播放器依赖于CD才能完成它的使命。
为了在Spring中阐述这个例子,让我们首先在Java中建立CD的概念。程序清单2.1展现了CompactDisc,它是定义CD的一个接口:
CompactDisc的具体内容并不重要,重要的是你将其定义为一个接口。作为接口,它定义了CD播放器对一盘CD所能进行的操作。---->它将CD播放器的任意实现与CD本身的耦合降低到了最小的程度。 我们还需要一个CompactDisc的实现,实际上,我们可以有CompactDisc接口的多个实现。在本例中,我们首先会创建其中的一个实现,也就是程序清单2.2所示的SgtPeppers类:
程序清单2.2 带有@Component注解的CompactDisc实现类SgtPeppers
和CompactDisc接口一样,SgtPeppers的具体内容并不重要。你需要注意的就是SgtPeppers类上使用了@Component注解。这个简单的注解表明该类会作为组件类,并告知Spring要为这个类创建bean。没有必要显式配置SgtPeppersbean,因为这个类使用了@Component注解,所以Spring会为你把事情处理妥当。
不过,组件扫描默认是不启用的。我们还需要显式配置一下Spring,从而命令它去寻找带有@Component注解的类,并为其创建bean。程序清单2.3的配置类展现了完成这项任务的最简洁配置。
程序清单2.3 @ComponentScan注解启用了组件扫描
类CDPlayerConfig通过Java代码定义了Spring的装配规则。
在2.3节中,我们还会更为详细地介绍基于Java的Spring配置。不过,现在我们只需观察一下CDPlayerConfig类并没有显式地声明任何bean,只不过它使用了@ComponentScan注解,这个注解能够在Spring中启用组件扫描。如果没有其他配置的话,@ComponentScan默认会扫描与配置类相同的包。因为CDPlayerConfig类位于soundsystem包中,因此Spring将会扫描这个包以及这个包下的所有子包,查找带有@Component注解的类。这样的话,就能发现CompactDisc,并且会在Spring中自动为其创建一个bean。
或者如果你更倾向于使用XML来启用组件扫描的话,那么可以使用Spring context命名空间的元素。程序清单2.4展示了启用组件扫描的最简洁XML配置。程序清单2.4 通过XML启用组件扫描:
尽管我们可以通过XML的方案来启用组件扫描,但是在后面的讨论中,我更多的还是会使用基于Java的配置。
可能有点让人难以置信,我们只创建了两个类,就能对功能进行一番尝试了。为了测试组件扫描的功能,我们创建一个简单的JUnit测试,它会创建Spring上下文,并判断CompactDisc是不是真的创建出来了。程序清单2.5中的CDPlayerTest就是用来完成这项任务的。
程序清单2.5 测试组件扫描能够发现CompactDisc
CDPlayerTest使用了Spring的SpringJUnit4ClassRunner,以便在测试开始的时候自动创建Spring的应用上下文。
注解@ContextConfiguration会告诉它需要在CDPlayerConfig中加载配置。因为CDPlayerConfig类中包含了@ComponentScan,因此最终的应用上下文中应该包含CompactDisc bean。
为了证明这一点,在测试代码中有一个CompactDisc类型的属性,并且这个属性带有@Autowired注解,以便于将CompactDisc bean注入到测试代码之中(稍后,我会讨论@Autowired)。
尽管我们只用它创建了一个bean,但同样是这么少的配置能够用来发现和创建任意数量的bean。在soundsystem包及其子包中,所有带有@Component注解的类都会创建为bean。只添加一行@ComponentScan注解就能自动创建无数个bean,这种权衡还是很划算的。
现在,我们会更加深入地探讨@ComponentScan和@Component,看一下使用组件扫描还能做些什么。
网友评论