本文借鉴: Spring 学习 https://www.cnblogs.com/wmyskxz/p/8830632.html (特此感谢!)
一, 配置 Bean 的方式及选择
配置方式
在 xml 文件中显式配置
在 Java 的接口和类中实现配置
隐式 Bean 的发现机制和自动装配原则
方式选择的原则
最优先: 通过隐式 Bean 的发现机制和自动装配的原则.
基于约定优于配置的原则, 这种方式应该是最优先的
好处: 减少程序开发者的决定权, 简单又不失灵活.
其次: Java 接口和类中配置实现配置
在没有办法使用自动装配原则的情况下应该优先考虑此类方法
好处: 避免 xml 配置的泛滥, 也更为容易.
典型场景: 一个父类有多个子类, 比如学生类有两个子类, 一个男学生类和女学生类, 通过 IoC 容器初始化一个学生类, 容器将无法知道使用哪个子类去初始化, 这个时候可以使用 Java 的注解配置去指定.
最后: xml 方式配置
在上述方法都无法使用的情况下, 那么也只能选择 xml 配置的方式.
好处: 简单易懂(当然, 特别是对于初学者)
典型场景: 当使用第三方类的时候, 有些类并不是我们开发的, 我们无法修改里面的代码, 这个时候就通过 xml 的方式配置使用了.
二, 通过 xml 配置装配 Bean
1,xml 配置前言
使用 xml 装配 Bean 需要定义对应的 xml, 这里需要引入对应的 xml 模式 (XSD) 文件, 这些文件会定义配置 Spring Bean 的一些元素, 当我们在 IDEA 中创建 xml 文件时, 会有友好的提示:
一个简单的 xml 配置文件如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
- </beans>
这就只是一个格式文件, 引入了一个 beans 的定义, 引入了 xsd 文件, 它是一个根元素, 这样它所定义的元素将可以定义对应的 Spring Bean.
2, 装配简易值
先来一个最简单的装配:
- <bean id="c" class="pojo.Category">
- <property name="name" value="测试" />
- </bean>
简单解释一下:
•id 属性是 Spring 能找到当前 Bean 的一个依赖的编号, 遵守 xml 语法的 ID 唯一性约束. 必须以字母开头, 可以使用字母, 数字, 连字符, 下划线, 句号, 冒号, 不能以 开头. 不过 id 属性不是一个必需的属性, name 属性也可以定义 bean 元素的名称, 能以逗号或空格隔开起多个别名, 并且可以使用很多的特殊字符, 比如在 Spring 和 Spring MVC 的整合中, 就得使用 name 属性来定义 bean 的名称, 并且使用 / 开头.
PS: 从 Spring 3.1 开始, id 属性也可以是 String 类型了, 也就是说 id 属性也可以使用 / 开头, 而 bean 元素的 id 的唯一性由容器负责检查.
如果 id 和 name 属性都没有声明的话, 那么 Spring 将会采用 "全限定名 #{number}" 的格式生成编号. 例如这里, 如果没有声明 "id="c""的话, 那么 Spring 为其生成的编号就是是"pojo.Category#0", 当它第二次声明没有 id 属性的 Bean 时, 编号就是"pojo.Category#1", 以此类推.
•class 属性显然就是一个类的全限定名
•property 元素是定义类的属性, 其中的 name 属性定义的是属性的名称, 而 value 是它的值.
这样的定义很简单, 但是有时候需要注入一些自定义的类, 比如之前饮品店的例子, JuickMaker 需要用户提供原料信息才能完成 juice 的制作:
- <!-- 配置 srouce 原料 -->
- <bean name="source" class="pojo.Source">
- <property name="fruit" value="橙子"/>
- <property name="sugar" value="多糖"/>
- <property name="size" value="超大杯"/>
- </bean>
- <bean name="juickMaker" class="pojo.JuiceMaker">
- <!-- 注入上面配置的 id 为 srouce 的 Srouce 对象 -->
- <property name="source" ref="source"/>
- </bean>
这里先定义了一个 name 为 source 的 Bean, 然后再制造器中通过 ref 属性去引用对应的 Bean, 而 source 正是之前定义的 Bean 的 name , 这样就可以相互引用了.
•ref 注入对象
3, 装配集合
有些时候我们需要装配一些复杂的东西, 比如 Set,Map,List,Array 和 Properties 等, 为此我们在 Packge[pojo] 下新建一个 ComplexAssembly 类:
- package pojo;
- import java.util.List;
- import java.util.Map;
- import java.util.Properties;
- import java.util.Set;
- public class ComplexAssembly {
- private Long id;
- private List<String> list;
- private Map<String, String> map;
- private Properties properties;
- private Set<String> set;
- private String[] array;
- /* setter and getter */
- }
这个 Bean 没有任何的实际意义, 只是为了介绍如何装配这些常用的集合类:
- <bean id="complexAssembly" class="pojo.ComplexAssembly">
- <!-- 装配 Long 类型的 id -->
- <property name="id" value="1"/>
- <!-- 装配 List 类型的 list -->
- <property name="list">
- <list>
- <value>value-list-1</value>
- <value>value-list-2</value>
- <value>value-list-3</value>
- </list>
- </property>
- <!-- 装配 Map 类型的 map -->
- <property name="map">
- <map>
- <entry key="key1" value="value-key-1"/>
- <entry key="key2" value="value-key-2"/>
- <entry key="key3" value="value-key-2"/>
- </map>
- </property>
- <!-- 装配 Properties 类型的 properties -->
- <property name="properties">
- <props>
- <prop key="prop1">value-prop-1</prop>
- <prop key="prop2">value-prop-2</prop>
- <prop key="prop3">value-prop-3</prop>
- </props>
- </property>
- <!-- 装配 Set 类型的 set -->
- <property name="set">
- <set>
- <value>value-set-1</value>
- <value>value-set-2</value>
- <value>value-set-3</value>
- </set>
- </property>
- <!-- 装配 String[]类型的 array -->
- <property name="array">
- <array>
- <value>value-array-1</value>
- <value>value-array-2</value>
- <value>value-array-3</value>
- </array>
- </property>
- </bean>
总结:
List 属性为对应的 <list> 元素进行装配, 然后通过多个 <value> 元素设值
Map 属性为对应的 <map> 元素进行装配, 然后通过多个 <entry> 元素设值, 只是 entry 包含一个键值对 (key-value) 的设置
Properties 属性为对应的 <properties> 元素进行装配, 通过多个 <property> 元素设值, 只是 properties 元素有一个必填属性 key , 然后可以设置值
Set 属性为对应的 <set> 元素进行装配, 然后通过多个 <value> 元素设值
对于数组而言, 可以使用 <array> 设置值, 然后通过多个 <value> 元素设值.
上面看到了对简单 String 类型的各个集合的装载, 但是有些时候可能需要更为复杂的装载, 比如一个 List 可以是一个系列类的对象, 为此需要定义注入的相关信息, 其实跟上面的配置没什么两样, 只不过加入了 ref 这一个属性而已.
集合注入总结:
List 属性使用 <list> 元素定义注入, 使用多个 <ref> 元素的 Bean 属性去引用之前定义好的 Bean
- <property name="list">
- <list>
- <ref bean="bean1"/>
- <ref bean="bean2"/>
- </list>
- </property>
Map 属性使用 <map> 元素定义注入, 使用多个 <entry> 元素的 key-ref 属性去引用之前定义好的 Bean 作为键, 而用 value-ref 属性引用之前定义好的 Bean 作为值
- <property name="map">
- <map>
- <entry key-ref="keyBean" value-ref="valueBean"/>
- </map>
- </property>
Set 属性使用 <set> 元素定义注入, 使用多个 <ref> 元素的 bean 去引用之前定义好的 Bean
- <property name="set">
- <set>
- <ref bean="bean"/>
- </set>
- </property>
4, 命名空间装配
除了上述的配置之外, Spring 还提供了对应的命名空间的定义, 只是在使用命名空间的时候要先引入对应的命名空间和 xml 模式 (XSD) 文件.
c - 命名空间
c - 命名空间是在 Spring 3.0 中引入的, 它是在 xml 中更为简洁地描述构造器参数的方式, 要使用它的话, 必须要在 xml 的顶部声明其模式:
PS: 是通过构造器参数的方式
现在假设我们现在有这么一个类:
- package pojo;
- public class Student {
- int id;
- String name;
- public Student(int id, String name) {
- this.id = id;
- this.name = name;
- }
- // setter and getter
- }
在 c - 命名空间和模式声明之后, 我们就可以使用它来声明构造器参数了:
- <!-- 引入 c - 命名空间之前 -->
- <bean name="student1" class="pojo.Student">
- <constructor-arg name="id" value="1" />
- <constructor-arg name="name" value="学生 1"/>
- </bean>
- <!-- 引入 c - 命名空间之后 -->
- <bean name="student2" class="pojo.Student"
- c:id="2" c:name="学生 2"/>
c - 命名空间属性名以 "c:" 开头, 也就是命名空间的前缀. 接下来就是要装配的构造器参数名, 在此之后如果需要注入对象的话则要跟上 -ref(如 c:card-ref="idCard1", 则对 card 这个构造器参数注入之前配置的名为 idCard1 的 bean)
很显然, 使用 c - 命名空间属性要比使用 <constructor-arg> 元素精简, 并且会直接引用构造器之中参数的名称, 这有利于我们使用的安全性.
我们有另外一种替代方式:
<bean name="student2" class="pojo.Student" c:_0="3" c:_1="学生 3"/>
我们将参数的名称替换成了 "0" 和 "1" , 也就是参数的索引. 因为在 xml 中不允许数字作为属性的第一个字符, 因此必须要添加一个下划线来作为前缀.
p - 命名空间
c - 命名空间通过构造器注入的方式来配置 bean,p - 命名空间则是用 setter 的注入方式来配置 bean , 同样的, 我们需要引入声明:
然后我们就可以通过 p - 命名空间来设置属性:
- <!-- 引入 p - 命名空间之前 -->
- <bean name="student1" class="pojo.Student">
- <property name="id" value="1" />
- <property name="name" value="学生 1"/>
- </bean>
- <!-- 引入 p - 命名空间之后 -->
- <bean name="student2" class="pojo.Student"
- p:id="2" p:name="学生 2"/>
我们需要先删掉 Student 类中的构造函数, 不然 xml 约束会提示我们配置 <constructor-arg> 元素.
同样的, 如果属性需要注入其他 Bean 的话也可以在后面跟上 -ref:
<bean name="student2" class="pojo.Student" p:id="2" p:name="学生 2" p:cdCard-ref="cdCard1"/>
util - 命名空间
工具类的命名空间, 可以简化集合类元素的配置, 同样的我们需要引入其声明(无需担心怎么声明的问题, IDEA 会有很友好的提示):
我们来看看引入前后的变化:
- <!-- 引入 util - 命名空间之前 -->
- <property name="list">
- <list>
- <ref bean="bean1"/>
- <ref bean="bean2"/>
- </list>
- </property>
- <!-- 引入 util - 命名空间之后 -->
- <util:list id="list">
- <ref bean="bean1"/>
- <ref bean="bean2"/>
- </util:list>
下表提供了 util - 命名空间提供的所有元素:
5, 引入其他配置文件
在实际开发中, 随着应用程序规模的增加, 系统中 <bean> 元素配置的数量也会大大增加, 导致 applicationContext.xml 配置文件变得非常臃肿难以维护.
解决方案
让 applicationContext.xml 文件包含其他配置文件即可 使用 <import> 元素引入其他配置文件
[1] 在[src] 文件下新建一个 bean.xml 文件, 写好基础的约束, 把 applicationContext.xml 文件中配置的 <bean> 元素复制进去
[2] 在 applicationContext.xml 文件中写入
<import resource="bean.xml" />
[3] 运行测试代码, 仍然能正确获取到 bean
Spring 学习(五)bean 装配详解之 [xml 方式配置]
来源: http://www.bubuko.com/infodetail-3198425.html