——基于XML的配置
依赖注入
spring 依赖注入的方式有,属性注入和构造函数注入,还有不常用到的工厂方法注入。
(1)属性注入
属性注入要求 Bean 提供默认的构造函数,并为需要的属性提供 set 方法,spring 先调用 Bean 的默认构造函数实例化 Bean 对象,然后通过反射的方法调用 set 方法注入属性值。如下简单的范例:
public class Phone { private int id; private String name; private double price; public Phone() { } public Phone(int id, double price, String name) { this.id = id; this.price = price; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } }
<bean id="phone" class="com.bean.Phone" > <property name="id"><value>007</value></property> <property name="name"><value>"华为"</value></property> <property name="price"><value>4999</value></property> </bean>
简化书写:
<bean id="phone" class="com.bean.Phone" > <property name="id" value="007"/> <property name="name" value="华为"/> <property name="price" value="4999" /> </bean>
通过命名空间 p 进一步简化, xmlns:p="http://www.springframework.org/schema/p"
如下:
<bean id="phone" class="com.bean.Phone" p:id="007" p:name="华为" p:price="4999" p:time-ref="date" />
p:属性-ref 表示引用。
(2)构造函数注入
使用构造注入的前提存在对应的有参构造函数。
public Phone(int id, double price, String name) { this.id = id; this.price = price; this.name = name; }
1、按类型匹配入参
<bean id="phone" class="com.bean.Phone" > <constructor-arg type="int" value="007"/> <constructor-arg type="java.lang.String" value="华为"/> <constructor-arg type="double" value="4999"/> </bean>
2、按索引匹配入参
第一个参数的索引是 0
<bean id="phone" class="com.bean.Phone" > <constructor-arg index="0" value="007"/> <constructor-arg index="2" value="华为"/> <constructor-arg index="1" value="4999"/> </bean>
3、按类型和索引匹配入参
带参的构造函数很多时,容易发生歧义,用这种联合的方式匹配入参会更加的明确。
<constructor-arg index="2" type="java.lang.String" value="华为"/>
4、自动类型反射匹配入参
当类型都是可以辨别,不会产生歧义,才能这样使用。
<bean id="time" class="java.util.Date"/> <bean id="phone" class="com.bean.Phone" > <constructor-arg type="java.util.Date" ref="time" /> <constructor-arg value="华为"/> </bean>
以上都是对应基本数据类型,当属性是引用类型应采用如下的配置方式。
给 Phone 添加属性: Date time;
<constructor-arg type="java.util.Date" ref="time" />
或
<constructor-arg type="java.util.Date"> <ref bean="time"/> </constructor-arg>
当构造函数配置 Bean A 的实例化,需要引用一个Bean B 的实例化,而 Bean B 也采用构造函数注入并且需要引用一Bean A 的实例化,这样就容易造成循环依赖发生死锁。——用属性注入就不会产生这个问题。
(3)工厂方法注入
工厂类对外屏蔽类的具体实例化步骤,调用者甚至无需知道具体的目标类是什么。
1、非静态工厂方法
实例化工厂类才可以调用工厂类中的方法。工厂方法如下:
public class PhoneFactory { public Phone creatPhone(){ Phone phone = new Phone(“007”,"华为",“4999”); return phone; } }
通过工作方法注入。
<bean id="factory" class="com.bean.PhoneFactory"/> <bean id="phone" factory-bean="factory" factory-method="creatPhone"/>
实例化工厂类,factory-bean 引用这个工厂的实例化,通过 factory-method 指定对应的工厂方法。
2、静态工厂方法
public class PhoneFactory { public static Phone creatPhone(){ Phone phone = new Phone("华为",new Date()); return phone; } }
使用静态工厂的方法,无须在配置文件实例化工厂类,按如下配置即可:
<bean id="phone" class="com.bean.PhoneFactory" factory-method="creatPhone"/>
class 属性指定工厂类的全包名,然后通过 factory-bean 指定对应的工厂方法。
注入参数详解
在 spring 配置文件中,不仅可以将基本数据类型、String、等字面量注入 Bean ,还可以将集合(List、Map)和其它定义的 Bean 注入 Bean 中。
(1)字面值
指的是可以用字符串表示值,这些值可以通过<value></value>进行注入。一般情况下,基本数据类型及其封装类、Sring等类型均可以采用字面值注入的方式,spring 容器为字面值提供了编辑器,将以字符串表示的字面值转换相应的内部变量类型。
XML中共有5个特殊的字符,分别是 & 、< 、> 、" 、’ 。如果需要注入值包含这些特殊字符,就需要用 <value>![CDATA[ ]]</value>
(2)引用其它 Bean
<bean id="phone" class="com.bean.Phone"> <constructor-arg index="0" value="007"/> <constructor-arg index="2" value="华为"/> <constructor-arg index="1" value="4999"/> </bean> <bean id="person" class="com.bean.Person"> <property name="name" value="张三"/> <property name="phone" ref="phone"/> </bean>
(3)null 值
用 <null/> 标签。 <property name="name"><null/></property>
(4)级联属性
<bean id="person" class="com.bean.Person"> <property name="name" value="张三"></property> <property name="phone.name" value="华为"/> <property name="phone.price" value="4999" /> </bean>
(5)内部 Bean
<bean id="person" class="com.bean.Person"> <property name="name" value="张三"></property> <property name="phone"> <bean class="com.bean.Phone"> <property name="name" value="华为"/> <property name="price" value="4999" /> </bean> </property> </bean>
(6)集合属性
<bean id="person" class="com.bean.Person"> <property name="names"> <set> <value>张三</value> <value>李四</value> </set> </property> <property name="phoneList"> <list> <ref bean="phone"/> <ref bean="phone2"/> </list> </property> <property name="map"> <map> <entry> <key><value>9527</value></key> <value>9527</value> </entry> </map> </property> </bean>
通过 util 命名空间,配置集合类型的 Bean。 xmlns:util="http://www.springframework.org/schema/util"
如下:
<bean id="person" class="com.bean.Person"> <property name="map"> <ref bean="map"/> </property> </bean> <util:map id="map"> <entry> <key><value>9527</value></key> <value>9527</value> </entry> </util:map>
(7)自动装配
<bean> 元素提供了一个自动装配的属性:autowire="【自动装配的类型】”
1. no:这是Spring框架的默认设置,在该设置下自动装配是关闭的,开发者需要自行在bean定义中用标签明确的设置依赖关系。
2. byName:该选项可以根据bean名称设置依赖关系。当向一个bean中自动装配一个属性时,容器将根据bean的名称自动在在配置文件中查询一个匹配的bean。如果找到的话,就装配这个属性,如果没找到的话就报错。
3. byType:该选项可以根据bean类型设置依赖关系。当向一个bean中自动装配一个属性时,容器将根据bean的类型自动在在配置文件中查询一个匹配的bean。如果找到的话,就装配这个属性,如果没找到的话就报错。
4. constructor:造器的自动装配和byType模式类似,但是仅仅适用于与有构造器相同参数的bean,如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。
5. autodetect:该模式自动探测使用构造器自动装配或者byType自动装配。首先,首先会尝试找合适的带参数的构造器,如果找到的话就是用构造器自动装配,如果在bean内部没有找到相应的构造器或者是无参构造器,容器就会自动选择byTpe的自动装配方式。
<beans>元素标签中 default-autowire 属性可以配置全局自动匹配。(byName,byType,constructor)
Bean 之间的关系
(1)继承
<bean id="phone1" class="com.bean.Phone" p:id="007" p:name="华为" p:price="4999" abstract="true"/> <!-- abstract true 表示Bean 不需要实例化 --> <bean id="phone3" parent="phone1" p:id="110" />
子类会继承父类Bean 的属性值,相同时子类将覆盖父类的值。
(2)依赖
Bean A 实例化是需要 Bean B 先实例化完成,才可以得到正常结果,那么在 Bean A 配置 <bean ...... depends-on = "a" /> ,这种方式就是显示指定 Bean A 的前置依赖。如果前置依赖多个可以通过空格、逗号、分号连接。
(3)引用
一个 bean 要引用另为一个 bean 的 id 属性值。
<bean id="phone" class="com.bean.Phone" p:id="007" p:name="华为" p:price="4999" /> <bean id="person" class="com.bean.Person"> <property name="phoneId"> <idref bean="phone"></idref> </property> </bean>
也就是说:phoneId = phone