Spring框架第三篇之基于XML的DI注入
一、注入分类
Bean实例在调用无参构造器创建空值对象后,就要对Bean对象的属性进行初始化。初始化是由容器自动完成的,称为注入。根据注入方式的不同,常用的有两类:设值注入、构造注入、实现特定接口注入。由于第三种方式采用侵入式编程,污染代码,所以几乎不用。
1、设值注入
设值注入是指,通过setter方法传入被调用者的实例。这种注入方式简单、直观,因而在Spring的依赖注入中大量使用。
关于设值注入举个简单的例子:
分别创建一个学校类(School):
/** * 学校类 * * @author Root */ public class School { private String name; public void setName(String name) { this.name = name; } @Override public String toString() { return "School [name=" + name + "]"; } }
学生类(Student):
/** * 学生类 * * @author Root */ public class Student { private String name; private int age; // 对象属性,也叫做域属性 private School school; public Student() { super(); } public void setName(String name) { System.out.println("执行setName()"); this.name = name; } public void setAge(int age) { System.out.println("执行setAge()"); this.age = age; } public void setSchool(School school) { this.school = school; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + ", school=" + school + "]"; } }
在配置文件中使用设值注入方式,设值对象属性值:
<?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"> <!-- 注册School --> <bean id="school" class="com.ietree.spring.basic.di.setter.School"> <property name="name" value="北京大学"></property> </bean> <!-- 注册Student --> <bean id="student" class="com.ietree.spring.basic.di.setter.Student"> <property name="name" value="李华"></property> <property name="age" value="20"></property> <!-- 域属性注入使用ref --> <property name="school" ref="school"></property> </bean> </beans>
注意:如果对象中包含有另外的对象引用,则需要使用ref,而不能使用value。
测试:
@Test public void test01(){ String resource = "com/ietree/spring/basic/di/setter/applicationContext.xml"; ApplicationContext ctx = new ClassPathXmlApplicationContext(resource); Student student = (Student) ctx.getBean("student"); System.out.println(student); }
程序输出:
执行setName()
执行setAge()
Student [name=李华, age=20, school=School [name=北京大学]]
2、构造注入
构造注入,顾名思义就是通过构造方法注入,举个简单的例子:
创建一个学校类(School):
/** * 学校类 * * @author Root */ public class School { private String name; public void setName(String name) { this.name = name; } @Override public String toString() { return "School [name=" + name + "]"; } }
学生类(Student):
/** * 学生类 * * @author Root */ public class Student { private String name; private int age; // 对象属性,也叫做域属性 private School school; /*public Student() { super(); }*/ // 代参构造器 public Student(String name, int age, School school) { super(); this.name = name; this.age = age; this.school = school; } public void setName(String name) { System.out.println("执行setName()"); this.name = name; } public void setAge(int age) { System.out.println("执行setAge()"); this.age = age; } public void setSchool(School school) { this.school = school; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + ", school=" + school + "]"; } }
配置文件:
<?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"> <!-- 注册School --> <bean id="school" class="com.ietree.spring.basic.di.constructor.School"> <property name="name" value="北京大学"></property> </bean> <!-- 注册Student --> <!-- 方式一 --> <!-- <bean id="student" class="com.ietree.spring.basic.di.constructor.Student"> <constructor-arg index="0" value="李华"/> <constructor-arg index="1" value="20"/> <constructor-arg index="2" ref="school"/> </bean> --> <!-- 方式二 --> <!-- <bean id="student" class="com.ietree.spring.basic.di.constructor.Student"> <constructor-arg value="李华"/> <constructor-arg value="20"/> <constructor-arg ref="school"/> </bean> --> <!-- 方式三:推荐--> <bean id="student" class="com.ietree.spring.basic.di.constructor.Student"> <constructor-arg name="name" value="李华"/> <constructor-arg name="age" value="20"/> <constructor-arg name="school" ref="school"/> </bean> </beans>
个人强烈推荐使用方式三,因为这样的配置方式不会带来歧义,关键是可读性比强两者要强。
测试:
@Test public void test01(){ String resource = "com/ietree/spring/basic/di/constructor/applicationContext.xml"; ApplicationContext ctx = new ClassPathXmlApplicationContext(resource); Student student = (Student) ctx.getBean("student"); System.out.println(student); }
程序输出:
Student [name=李华, age=20, school=School [name=北京大学]]
二、命名空间注入
命名空间注入分为两种,p命名空间和c命名空间。
例:
创建School类:
/** * 学校类 * * @author Root */ public class School { private String name; public School(String name) { super(); this.name = name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "School [name=" + name + "]"; } }
创建学生类(Student):
/** * 学生类 * * @author Root */ public class Student { private String name; private int age; // 对象属性,也叫做域属性 private School school; public Student() { super(); } public Student(String name, int age, School school) { super(); this.name = name; this.age = age; this.school = school; } public void setName(String name) { System.out.println("执行setName()"); this.name = name; } public void setAge(int age) { System.out.println("执行setAge()"); this.age = age; } public void setSchool(School school) { this.school = school; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + ", school=" + school + "]"; } }
配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 注册School --> <!-- <bean id="mySchool" class="com.ietree.spring.basic.di.namespace.School" p:name="清华大学"/> 注册Student <bean id="student" class="com.ietree.spring.basic.di.namespace.Student" p:name="李华" p:age="20" p:school-ref="mySchool"/> --> <!-- 注册School --> <bean id="mySchool" class="com.ietree.spring.basic.di.namespace.School" c:name="清华大学"/> <!-- 注册Student --> <bean id="student" class="com.ietree.spring.basic.di.namespace.Student" c:name="李华" c:age="20" c:school-ref="mySchool"/> </beans>
注意:
1、这里如果要想使用这两种命名空间方式的话,需要先导入约束:
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
2、如果是使用c命名空间的方式的话,在类里面还必须写上带参构造器。
三、集合属性注入
创建School类:
/** * 学校类 * * @author Root */ public class School { private String name; public void setName(String name) { this.name = name; } @Override public String toString() { return "School [name=" + name + "]"; } }
创建Some类:
import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; public class Some { private School[] schools; private String[] myStr; private List<String> myList; private Set<String> mySet; private Map<String, Object> myMap; private Properties myProps; public void setSchools(School[] schools) { this.schools = schools; } public void setMyStr(String[] myStr) { this.myStr = myStr; } public void setMyList(List<String> myList) { this.myList = myList; } public void setMySet(Set<String> mySet) { this.mySet = mySet; } public void setMyMap(Map<String, Object> myMap) { this.myMap = myMap; } public void setMyProps(Properties myProps) { this.myProps = myProps; } @Override public String toString() { return "Some [schools=" + Arrays.toString(schools) + ", myStr=" + Arrays.toString(myStr) + ", myList=" + myList + ", mySet=" + mySet + ", myMap=" + myMap + ", myProps=" + myProps + "]"; } }
配置applicationContext.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"> <!-- 注册School --> <bean id="mySchool" class="com.ietree.spring.basic.di.list.School"> <property name="name" value="北京大学"></property> </bean> <bean id="mySchool2" class="com.ietree.spring.basic.di.list.School"> <property name="name" value="清华大学"></property> </bean> <!-- 注册Student --> <bean id="some" class="com.ietree.spring.basic.di.list.Some"> <property name="schools"> <array> <ref bean="mySchool"/> <ref bean="mySchool2"/> </array> </property> <property name="myStr"> <array> <value>中国</value> <value>广东</value> </array> </property> <property name="myList"> <list> <value>深圳</value> <value>龙岗</value> </list> </property> <property name="mySet"> <set> <value>坂田</value> <value>天安云谷</value> </set> </property> <property name="myMap"> <map> <entry key="mobile" value="123456"></entry> <entry key="weChat" value="654321"></entry> </map> </property> <property name="myProps"> <props> <prop key="edu">本科</prop> <prop key="gender">性别</prop> </props> </property> </bean> </beans>
方式二:
<?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"> <!-- 注册School --> <bean id="mySchool" class="com.ietree.spring.basic.di.list.School"> <property name="name" value="北京大学"></property> </bean> <bean id="mySchool2" class="com.ietree.spring.basic.di.list.School"> <property name="name" value="清华大学"></property> </bean> <!-- 注册Student --> <bean id="some" class="com.ietree.spring.basic.di.list.Some"> <property name="schools"> <array> <ref bean="mySchool"/> <ref bean="mySchool2"/> </array> </property> <property name="myStr" value="中国,广东"/> <property name="myList" value="深圳,龙岗"/> <property name="mySet" value="坂田,天安云谷"/> <property name="myMap"> <map> <entry key="mobile" value="123456"></entry> <entry key="weChat" value="654321"></entry> </map> </property> <property name="myProps"> <props> <prop key="edu">本科</prop> <prop key="gender">性别</prop> </props> </property> </bean> </beans>
四、对于域属性的自动注入
<!-- 注册Student autowire="byName":通过字段名注入 autowire="byType":通过字段类型注入 --> <bean id="student" class="com.ietree.spring.basic.di.domain.Student" autowire="byName"> <property name="name" value="李华"></property> <property name="age" value="20"></property> </bean>
五、使用SPEL注入
SPEL,Spring Expression Language,即Spring EL表达式语言。即,在Spring配置文件中为Bean属性注入值时,可直接使用SPEL表达式计算的结果。SPEL表达式以#开头,后跟一对大括号。
举例:
创建Person类:
package com.ietree.spring.basic.di.spel; public class Person { private String pname; private int page; public Person() { super(); } public void setPname(String pname) { this.pname = pname; } public void setPage(int page) { this.page = page; } public String getPname() { return pname; } public int getPage() { return page; } public int computeAge() { return this.page > 25 ? 25 : this.page; } @Override public String toString() { return "Person [pname=" + pname + ", page=" + page + "]"; } }
创建Student类:
package com.ietree.spring.basic.di.spel; /** * 学生类 * * @author Root */ public class Student { private String name; private int age; public Student() { super(); } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } }
配置ApplicationContext.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"> <bean id="myPerson" class="com.ietree.spring.basic.di.spel.Person"> <property name="pname" value="李华"></property>
<!-- 随机生成0 - 99数字 --> <property name="page" value="#{T(java.lang.Math).random() * 100}"></property> </bean> <bean id="myStudent" class="com.ietree.spring.basic.di.spel.Student"> <property name="name" value="#{myPerson.pname}"></property> <!-- <property name="age" value="#{myPerson.page > 25 ? 25 : myPerson.page}"></property> --> <property name="age" value="#{myPerson.computeAge() }"></property> </bean> </beans>
六、使用内部Bean注入
<?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"> <!-- 注册School --> <!-- <bean id="school" class="com.ietree.spring.basic.di.inner.School"> <property name="name" value="北京大学"></property> </bean> --> <!-- 注册Student --> <bean id="student" class="com.ietree.spring.basic.di.inner.Student"> <property name="name" value="李华"></property> <property name="age" value="20"></property> <property name="school"> <bean class="com.ietree.spring.basic.di.inner.School"> <property name="name" value="清华大学"></property> </bean> </property> </bean> </beans>
七、使用同类抽象Bean注入
<?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"> <!-- 同类抽象Bean --> <bean id="baseStudent" class="com.ietree.spring.basic.di.sameextends.Student" abstract="true"> <property name="school" value="清华大学"/> <property name="department" value="计算机系"/> </bean> <bean id="student1" parent="baseStudent"> <property name="name" value="小明"/> <property name="age" value="21"/> </bean> <bean id="student2" parent="baseStudent"> <property name="name" value="张三"/> <property name="age" value="22"/> </bean> <bean id="student3" parent="baseStudent"> <property name="name" value="李四"/> <property name="age" value="23"/> </bean> </beans>
八、使用异类抽象Bean注入
<?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"> <!-- 异类抽象Bean --> <bean id="baseStudent" abstract="true"> <property name="school" value="清华大学"/> <property name="department" value="计算机系"/> </bean> <bean id="student" class="com.ietree.spring.basic.di.sameextends.Student" parent="baseStudent"> <property name="name" value="小明"/> <property name="age" value="21"/> </bean> <bean id="teacher" class="com.ietree.spring.basic.di.sameextends.Teacher" parent="baseStudent"> <property name="name" value="李四"/> <property name="age" value="23"/> </bean> </beans>
九、为应用指定多个Spring配置文件
1、同级关系:
测试:
package com.ietree.spring.basic.di.mulxml; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test public void test01() { /*String resource1 = "com/ietree/spring/basic/di/setter/spring-base.xml"; String resource2 = "com/ietree/spring/basic/di/setter/spring-beans.xml"; ApplicationContext ctx = new ClassPathXmlApplicationContext(resource1, resource2);*/ String resource = "com/ietree/spring/basic/di/setter/spring-*.xml"; ApplicationContext ctx = new ClassPathXmlApplicationContext(resource); Student student = (Student) ctx.getBean("student"); System.out.println(student); } }
2、包含关系:
<?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"> <import resource="classpath:com/ietree/spring/basic/di/mulxml/spring-base.xml"/> <import resource="classpath:com/ietree/spring/basic/di/mulxml/spring-beans.xml"/> </beans>