这篇文章来自个人博客spring
上一篇文章已经介绍了 Bean 的基本概念,因此今天这篇文章是基于上一篇中 Bean 的三种装配方式来进一步探讨,内容中会穿插着基础的依赖注入的概念express
主要内容bash
- 自动装配
- 使用 XML 装配
- 使用 Java 装配
上一篇文章中使用注解定义 Bean 的时候都是在类的定义上加注解,小写的类名做为 Bean 的 ID,可是咱们能够本身命名 Bean:学习
设置组件的值为 Bean 的名字,若是这么作了,在测试中就找不到名为“student”的 Bean 了:测试
将测试中获取的 Bean 的名字改成“myBean”以后就能经过测试了ui
上次讲到了组件扫描,设置组件扫描的方式有两种:spa
咱们再还原 student 这个 Bean 的状态,也就是在类的定义上加一个注解 @Component:3d
在配置文件中添加组建扫描:code
这个是上次讲过的,就再也不多说,而后来看看 Java 配置类的组件扫描:cdn
添加的注解 @Component 带一个参数,指定了扫描的包的位置,就至关于 XML 配置文件中的 base-package 属性
若是不填写参数,就扫描此文件所在的包,在这里,咱们扫描名为“bean”的包,点击注解左边的那个按钮就能跳转到 Student 类(bean 包中)
此处引用《Spring实战》的一句话:
简单来讲,自动装配就是让 Spring 自动知足 Bean 依赖的一种方法,在知足依赖的过程当中,会在 Spring 应用上下文中寻找匹配某个 Bean 需求的其余 Bean
咱们这里添加一个接口 Book,至于为何用接口而不用实现类,由于咱们后文要对这个接口作多个实现:
而后建立一个实现了 Book 接口的类,而且将其做为一个 Bean:
既然是自动装配,确定要用到注解 @Autowired,那么,这个注解能够用在什么地方呢?
第一点以前说过,在实例化时候添加这个注解进行自动装配
咱们修改一下 Student 类:
在构造 Student 的时候,我将一个 Book 类注入,由于咱们刚才已经有了 Book 类的实现,因此这里注入的是 englishBook 这个 Bean
须要注意的是:Spring 在建立 student 这个 Bean 的时候,会传入一个 Book 类型的 Bean
有两种状况会致使抛出异常,没有所匹配的 Bean 或有多个所匹配的 Bean
为了验证第一种状况,我将 EnglishBook 的 @Component 注解去掉,这样子就没有 Book 类型的 Bean 了
运行测试以后,看到两条主要的错误信息:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'student' defined in file [C:\Users\94545\Desktop\Developer Folder\Java Test Folder\springtest\out\production\springtest\bean\Student.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'bean.Book' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'bean.Book' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
首先是名为“student” 的 Bean 的构造器中的依赖关系出错了,第二是没有 Book 类型的 Bean,致使 Student 的 Bean 的构造器中条件不符合
为了验证第二种状况,我将代码还原,而且建立另外一个 Book 类型的 Bean:mathBook,在此状况下,测试是不会经过的,由于没有单一符合条件的 Bean
测试后,证明了注解有效:
这个注解对于构造器注入是不可用的,接下来在 Setter 方法上装配的时候再讲解
咱们须要修改一下 Student 类,而且暂时隐藏一下 mathBook 这个 Bean:
带有 @Autowired 注解,在实例化时可以自动匹配 Book 类型的 Bean:
关于 Setter 方法和构造器来装配 Bean,就目前的学习状况来讲,只有一点区别,若是有多个不一样类型的 Bean,使用构造器可以指定装配的顺序
如今咱们还原 mathBook 这个 Bean,若是出现上述的两个可能抛出异常的状况,这里有两种解决方式:
和上述相似,很少说
而后就能打印出英语书的信息(不截图了)
这个注解有一点灵活的地方就是,可以在 Bean 的定义上设置限定符,也就是说,限定符不必定要是 Bean 的名字,作个测试:
这时候,若是还使用 englishBook 做为限定符,也可以定位到这个 Bean,可是咱们用自定义的限定符也能够,修改 Setter 方法上的限定符,进行测试:
证实使用 testQualifier 做为限定符也能获得结果
使用 XML 装配也有分构造器注入仍是设值注入(Setter)方法,接下来的前三个使用的是构造器注入
将自动装配部分添加的注解取消掉,把代码还原成初始状态,而后咱们开始使用 XML 装配:
暂时不配置 mathBook 这个 Bean,并修改 StudentTest 的上下文配置信息:
最后即是 Bean 的配置文件:
首先建立 englishBook 这个 Bean,在建立 student 这个 Bean,这里有一个元素
<constructor-arg ref=""/>
复制代码
由于我在 student 的构造器中有一个名叫 englishBook 的Bean 做为参数,因此 Spring 会建立一个 ID 为 englishBook 的Bean,并将其引用传递至 student 的构造器中,ref 属性代表了传递引用的 Bean 的ID
若是我在 student 的构造器中传入的不是某个 Bean 的引用,而是某个字符串呢?
修改 XML 文件中的配置信息:
value 属性表示的是构造器中的字面量的值,能够是字符串、数字或布尔值等
而后测试一下:
证实字面量被成功注入了
一个学生不可能只有一本书,因此咱们要考虑,如何传入列表呢?
首先咱们先修改 Student 类,传入的参数不只是字符串,还有一个存放书本的列表:
而后在 XML 文件中配置 Bean:
<bean id="englishBook" class="bean.EnglishBook"/>
<bean id="mathBook" class="bean.MathBook"/>
复制代码
最后配置 student 这个 Bean,而且配置构造器参数:
<bean id="student" class="bean.Student">
<constructor-arg value="I have some books"/>
<constructor-arg>
<list>
<ref bean="englishBook"/>
<ref bean="mathBook"/>
</list>
</constructor-arg>
</bean>
复制代码
第一个参数是字符串,第二个是 Book 类型的 List,列表中存放的是刚才建立的两个 Bean 的引用,而后来进行测试:
若是列表中也存放字符串,而不是引用,在元素中使用属性来代替属性
修改 Student 类和 Bean 配置文件:
而后在 Bean 的配置文件中加上这么一句:
<bean id="student" class="bean.Student">
<property name="book" ref="englishBook"/>
</bean>
复制代码
属性是为 Setter 方法提供服务的,和上述的属性所提供的服务是同样的,在这个语句中,我在 book 中注入了 ID 为 englishBook 的 Bean 的引用,而后测试,会输出英语书的信息:
关于字面量和列表的注入,其实和构造器注入是相似的,将属性替换为,只不过,设置注入须要设置属性名,也就是将 a Bean 的引用(或字面量或集合)注入到 b 属性中,就再也不详述
除了使用 XML,还可以使用 Java 代码来装配 Bean 而且达到依赖注入的目的
因此咱们须要先修改测试中的上下文配置信息:
@ContextConfiguration(classes = StudentConfig.class)
复制代码
再将 Student 类改回构造器注入的类型:
使用 Java 进行 Bean 的装配在上一篇文章中已经提到,这里就说一说依赖注入的实现:
在 Java 配置类中定义两个 Bean:
在 student 中使用构造器注入了 englishBook 这个 Bean,运行测试,将会获得英语书的输出:
其实,这一篇文章把 Bean 的装配和依赖注入混合起来将了,可能有些人会以为乱,可是三种方式其实从思路来讲是相似的,经过认真地阅读这两篇关于 Bean 的介绍,就能对 Spring 的 DI 以及 IoC 有一个基本了解
DI(Dependency Injection)称为依赖注入,通俗的说,是在运行时,动态地知足某个对象对其余对象的需求,用上面的例子来讲,student 在运行时须要 Book 类型的 Bean 做为依赖,我就给它注入一个 Bean,叫作 englishBook,这就可以叫作依赖注入
IoC(Inversion of Control)称为控制反转,在上面作的全部测试中,我都没有手动建立某个对象的实例,好比说注入一个列表,我甚至都没有建立一个列表的实例,那么为何还会经过测试呢?由于 Spring 帮我在程序运行时建立了各个 Bean 的实例
IoC 可以由 DI 来实现,也就是说,程序中的各个组件之间的依赖关系都是由 Spring 来管理的,这就称做控制反转,这是 Spring 的核心
接下来还陆续会有文章来说述这一律念