文章目录
1、装配Bean概述
在平时的大部分开发场景中,我们都会使用org.springFramework.context.ApplicationContext的具体实现类,因为对应的Spring IoC容器功能相对强大。而在Spring中提供了3种方法进行配置:
- 在XML中显式配置
- 在Java的接口和类中实现配置
- 隐式Bean的发现机制和自动装配原则
在显示的开发中,这3中方式都会被用到,并且在学习和工作中常常混合使用,因此需要我们明白这三种方式的优先级,即我们应该如何选择使用哪种方式去把Bean发布到Spring IoC容器中。
第一,基于“约定优于配置”的原则,最优先的应该是通过隐式Bean的发现机制和自动装配的原则。这样的好处是减少程序开发者的决定权,简单又不失灵活。
第二,在没有办法使用自动装配原则的情况下应该优先考虑Java接口和类中实现配置,这样的好处是避免XML配置的泛滥,也更为容易。这种场景典型的例子是一个父类有多个子类,比如学生类有两个子类:男生类和女生类,通过IoC容器初始化一个学生类,容器将无法知道使用哪个子类去初始化,这个时候可以使用Java的注解配置去指定。
第三,在上述方法都无法使用的情况下,那么只能选择XML去配置Spring IoC容器。由于现实开发中常常用到第三方类库,有些类并不是我们开发的,我们无法修改里面的代码,这个时候就通过XML的方式配置使用了。
通俗来讲,当配置的类时你自身正在开发的工程,那么应该考虑Java配置为主,而Java配置又分为自动装配和Bean名称配置。在没有歧义的基础上,优先使用自动装配,这样就可以减少大量的XML配置。如果所需配置的类并不是你的工程开发的,那么建议使用XML的方式。
2、演示项目环境搭建
该演示项目开发环境为IDEA,Project名为“Spring Demo”。
首先,创建名为“BeanAssembling”的Spring Module,具体过程如下:
通过该种方式即可在IDEA中快速构建Spring开发环境。然后在lib文件夹中补充导入测试及日志jar包如下:
注意,这里采用的Junit的版本与上一篇博客中的版本不一致,该篇博客中使用的是Junit-4.12,之所以没有选择之前的版本,是因为由于之前的版本过低可能会导致在使用Spring上下文测试的时候出现异常,详细信息参考如下博客:
- spring+junit4时用Junit单元测试遇到的bug:java.lang.ExceptionInInitializerError.
- 【Junit】JUnit-4.12使用报java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing错误.
3、通过XML配置装配Bean
使用XML装配Bean需要定义对应的XML,这里需要引入对应的XML模式(XSD)文件,这些文件会定义配置Spring 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">
<!--Spring Bean配置代码-->
</beans>
在上述配置中引入了一个beans的定义,它是一个根元素,而XSD文件也被引入了,这样它所定义的元素将可以定义对应的Spring Bean。
3.1 装配简易值
首先,在com.ccff.spring.assembling.pojo包下创建一个Student类,具体代码如下:
package com.ccff.spring.assembling.pojo;
public class Student {
private String name;
private String sex;
private String studentNo;
private Integer age;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", studentNo='" + studentNo + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getStudentNo() {
return studentNo;
}
public void setStudentNo(String studentNo) {
this.studentNo = studentNo;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
然后在spring-config配置文件中对Student类进行装配,具体配置如下:
<?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">
<!--Spring Bean配置代码-->
<!--通过XML配置装配Bean:装配简易值-->
<bean id="student" class="com.ccff.spring.assembling.pojo.Student">
<property name="name" value="学生一" />
<property name="studentNo" value="S001" />
<property name="age" value="24" />
<property name="sex" value="男" />
</bean>
</beans>
其中,id属性时Spring找到的这个Bean的编号,不过id不是一个必需的属性,如果没有声明它,那么Spring将采用“全限定名#{number}”的格式生成编号。如果只声明一个这样的类,而没有声明id=“student”,那么Spring为其生成的编号就是“com.ccff.spring.assembling.pojo.Student#0”。当它第二次声明没有id属性的Bean时,编号就是“com.ccff.spring.assembling.pojo.Student#1”,但是一般我们都会选择自己定义id,因为自动生成的id会比较麻烦。
class属性显然是一个类全限定名。
property元素时定义类的属性,其中name属性定义的是属性名称,而value是其值。
在com.ccff.spring.assembling.test包下创建名为TestStudent的测试类,并在测试类中添加名为“TestEasyAssembingByXML”的测试方法,具体代码如下:
package com.ccff.spring.assembling.test;
import com.ccff.spring.assembling.pojo.Student;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestStudent {
private ApplicationContext context;
@Before
public void getContainer(){
context = new ClassPathXmlApplicationContext("spring-config.xml");
}
@Test
public void TestEasyAssembingByXML(){
Student student1 = (Student) context.getBean("student");
System.out.println(student1);
}
}
运行该测试方法后,查看输出到控制台的日志信息如下,则说明Student类的bean已经被创建。
这样的定义很简单,但是有时候需要注入一些自定义的类。例如每个学生有属于某一个学校,而学校可以单独抽象出一个类。在com.ccff.spring.assembling.pojo包下创建School类,具体代码如下所示:
package com.ccff.spring.assembling.pojo;
public class School {
private String school_name;
private String school_no;
private String school_location;
public String getSchool_name() {
return school_name;
}
public void setSchool_name(String school_name) {
this.school_name = school_name;
}
public String getSchool_no() {
return school_no;
}
public void setSchool_no(String school_no) {
this.school_no = school_no;
}
public String getSchool_location() {
return school_location;
}
public void setSchool_location(String school_location) {
this.school_location = school_location;
}
@Override
public String toString() {
return "School{" +
"school_name='" + school_name + '\'' +
", school_no='" + school_no + '\'' +
", school_location='" + school_location + '\'' +
'}';
}
}
然后,修改Student类,为其指定所属的学校,具体代码如下:
package com.ccff.spring.assembling.pojo;
public class Student {
private String name;
private String sex;
private String studentNo;
private Integer age;
private School school;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getStudentNo() {
return studentNo;
}
public void setStudentNo(String studentNo) {
this.studentNo = studentNo;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public School getSchool() {
return school;
}
public void setSchool(School school) {
this.school = school;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", studentNo='" + studentNo + '\'' +
", age=" + age +
", school=" + school +
'}';
}
}
由于增加了School类,因此需要在spring-config中先配置School类Bean。然后在配置的school bean中增加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">
<!--Spring Bean配置代码-->
<!--通过XML配置装配Bean:装配简易值-->
<bean id="school" class="com.ccff.spring.assembling.pojo.School">
<property name="school_name" value="中国科学院大学" />
<property name="school_no" value="Sch001" />
<property name="school_location" value="北京市怀柔区怀北镇怀北庄中国科学院大学雁西湖校区" />
</bean>
<bean id="student" class="com.ccff.spring.assembling.pojo.Student">
<property name="name" value="学生一" />
<property name="studentNo" value="S001" />
<property name="age" value="24" />
<property name="sex" value="男" />
<property name="school" ref="school" />
</bean>
</beans>
修改测试方法TestEasyAssembingByXML如下:
package com.ccff.spring.assembling.test;
import com.ccff.spring.assembling.pojo.School;
import com.ccff.spring.assembling.pojo.Student;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestStudent {
private ApplicationContext context;
@Before
public void getContainer(){
context = new ClassPathXmlApplicationContext("spring-config.xml");
}
@Test
public void TestEasyAssembingByXML(){
School school = (School) context.getBean("school");
System.out.println(school);
Student student1 = (Student) context.getBean("student");
System.out.println(student1);
}
}
这里先定义了一个id为school的Bean,然后在id为student的Bean中使用ref属性引用对应的Bean,而school正是之前创建的school的id,这样就可以相互引用了。
运行该测试方法后,查看输出到控制台的日志信息如下,则说明Student类的bean已经被创建。
3.2 装配集合
有些时候需要做一些复杂的装配工作,比如Set、Map、List、Array和Properties等。为了演示这些复杂的装配工作,首先在com.ccff.spring.assembling.pojo包中定义名为“ComplexAssembly”的类,具体代码如下:
package com.ccff.spring.assembling.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;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public Map<String, String> getMap() {
return map;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public Set<String> getSet() {
return set;
}
public void setSet(Set<String> set) {
this.set = set;
}
public String[] getArray() {
return array;
}
public void setArray(String[] array) {
this.array = array;
}
}
接下来在spring-config中完成这些复杂的装配工作,具体代码如下所示:
<?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">
<!--Spring Bean配置代码-->
<!--通过XML配置装配Bean:装配简易值-->
<bean id="school" class="com.ccff.spring.assembling.pojo.School">
<property name="school_name" value="中国科学院大学" />
<property name="school_no" value="Sch001" />
<property name="school_location" value="北京市怀柔区怀北镇怀北庄中国科学院大学雁西湖校区" />
</bean>
<bean id="student" class="com.ccff.spring.assembling.pojo.Student">
<property name="name" value="学生一" />
<property name="studentNo" value="S001" />
<property name="age" value="24" />
<property name="sex" value="男" />
<property name="school" ref="school" />
</bean>
<!--通过XML配置装配Bean:装配集合-->
<bean id="complexAssembly" class="com.ccff.spring.assembling.pojo.ComplexAssembly">
<property name="id" value="1" />
<property name="list">
<</