Spring装配bean有三种主要的装配方式:
- 在XML中进行显示配置
- 在Java中进行显示配置
- 隐式的bean发现机制与自动装配
关于依赖注入(DI)部分内容请去彭老斯的博客骚扰:浅析Spring的IoC和DI
以下案例均来自《spring实战(第4版)》第二章。截图均来自慕课视频Spring入门篇
其中,SgtPeppers为具体的bean,实现了CompactDisc接口,CDPLayer也为具体的bean,实现了MediaPlayer接口,但它需要依赖于SgtPeppers。CDPlayerConfig为配置类,用于JavaConfig方式或自动装配方式的部分配置,CDPlayerTest为测试类,用于测试是否装配成功。它们均在soundsystem包中。
前言
首先,什么是装配,书上的定义是:创建应用组件之间协作的行为。
在我的理解中,装配bean分为两个阶段,发现(注册)bean与连接bean(Spring注入),即spring IoC容器先要知道它将管理哪些bean,再将相互之间有关联的bean连接起来,如将一个bean的实例作为参数传给另一个bean的构造器或者setter方法等。
对于第一步,有两种方法,一是采用自动装配的@ComponentScan自动发现指定包下所有用@Component注解的bean,这种方法中,若未指定参数,则在当前包下寻找,反之则在作为参数的类所在的包下寻找,因此更优化的方式是在指定包下创建一个专门用来扫描的空接口。(当然,也可以采用XML配置context:component-scan标签)
二是手动指定注册哪些bean,即在XML 中配置bean标签或者@Configuration所注解的类中用@bean指定。
例如:
1 |
|
对于第二步,主要就是一般提及的三种情况:
自动装配
将需要被注册的bean用@Component注解,同时将需要被自动赋值的属性用@Autowired注解。这两个注解仅在自动装配中使用。
例如:
1 |
|
其中,@Autowired可以注解在属性上、构造器上、setter方法上,甚至是任何方法上,只要该方法可以为属性赋值即可。需注意,该注解可以传入required属性值,默认为true,若改为false,可以避免因未给属性赋初始值而报的错,但在后面的语句中可能造成空指针异常。(@Autowired也可以用Java依赖注入规范中的@Inject替代,两者差别非常小)
值得一提的是,自动装配出的bean的ID就是将该类的名称的第一个大写字母变为小写,若想改变ID,可以在@Component中指定。(也可以使用Java依赖注入规范中的@Named(…)替代,两者差别非常小)
基于JavaConfig的装配
如第一段代码所示,用@Bean指定将要注册哪些bean,bean之间具体的连接得手动配置。当然,这里面还有些小技巧,例如:
1 |
|
很明显,第一种方式的可重用性与可维护性高于第二种,因此我更倾向于使用接口来进行参数传递。
值得注意的是,带有@bean注解的方法可以采用任何必要的Java功能来产生bean实例,这里存在的可能性仅仅受到Java语言的限制。
另外,spring中默认bean都为单例,spring会拦截所有对它的调用,并确保直接返回该方法所创建的bean。
该方式装配出的bean的ID默认为方法名,若需修改,给@Bean的name参数赋值即可。
基于XML的装配
1 | <?xml version="1.0" encoding="UTF-8"?> |
该方式中,bean标签用于注册bean,constructor-arg标签与property标签用于连接具有依赖关系的bean,也可以用于为属性赋字面量。
1 | <bean id = "aaa" class = "aaa"> |
1 | <bean id = "aaa" class = "aaa"> |
当然,构造器注入与设值注入分别有对应的简写,即c-命名空间与p-命名空间,但它们不能传入集合,详见书。
此外,还有一种更实用的方式传入集合,及Spring util-命名空间,详见书。
至此,三种常用的bean装配方式就说完了,总结起来就是,需要刻意去发现bean的只有自动装配一种方式,基于JavaConfig与XML的配置方式在注册bean的时候同时会将bean之间的依赖关系通过各自的方式手动表示出来。