在Spring IOC/DI的学习中,核心的内容就是Bean装配及相关内容了。其中Bean配置有两种方式,分别是基于XML文件配置Bean和基于注解配置Bean,本篇总结这两种方式的基本使用。
一、基于XML文件配置Bean 1.1 全类名(反射)方式通过全类名的方式在IOC中创建Bean,先决条件是Bean中必须有无参构造方法。在XML文件中使用bean标签和id、class属性实例化Bean。
<bean id="bean标识" class="全类名">
...... //属性注入或构造器注入
</bean>
其中属性注入是通过<property>
标签,使用name指定属性名,value指定属性值,对Bean中的属性进行赋值。构造器注入是通过<constructor-arg>
标签,使用value为参数传值,为了区分重载的构造器,通常会配合使用type属性,指定参数的类型。如下案例,有Student和Course两个Bean,通过全类名方式对他们进行装配。
public class Student {
private String sname;
private int sno;
private Course course;
public Student() {
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public int getSno() {
return sno;
}
public void setSno(int sno) {
this.sno = sno;
}
public Course getCourse() {
return course;
}
public void setCourse(Course course) {
this.course = course;
}
@Override
public String toString() {
return "Student [sname=" + sname + ", sno=" + sno + ", course=" + course + "]";
}
}
public class Course {
private String cname;
private String tname;
public Course() {
}
public Course(String cname, String tname) {
super();
this.cname = cname;
this.tname = tname;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public String getTname() {
return tname;
}
public void setTname(String tname) {
this.tname = tname;
}
@Override
public String toString() {
return "Course [cname=" + cname + ", tname=" + tname + "]";
}
}
<?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="student" class="com.spring.beans.test.Student">
<property name="sno" value="101"></property>
<property name="sname" value="张三"></property>
<property name="course" ref="course1"></property>
<!--由于course属性是关联到Course类的,所以使用ref属性引用bean-->
</bean>
<bean id="course1" class="com.spring.beans.test.Course">
<constructor-arg type="java.lang.String">
<value><![CDATA[<c#程序设计>]]></value>
<!--假定字符串中包含与XML冲突的特殊字符,用CDATA进行处理-->
</constructor-arg>
<constructor-arg value="Mr.C" type="java.lang.String"></constructor-arg>
</bean>
</beans>
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
//1、创建spring的IOC容器对象,从类路径下加载文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-test.xml");
//2、从IOC容器对象中获取bean实例
Student student = (Student) ctx.getBean("student");
Course course = (Course) ctx.getBean("course1");
System.out.println(student);
System.out.println(course);
}
}
运行结果如下图所示:
也可以在student的bean中,通过级联的方式为course赋值,但首先还是要引用course的bean。如下代码所示:
<bean id="student" class="com.spring.beans.test.Student">
<property name="sno" value="101"></property>
<property name="sname" value="张三"></property>
<property name="course" ref="course1"></property>
<property name="course.cname" value="Java程序设计"></property>
<property name="course.tname" value="Mr.J"></property>
</bean>
一个学生可以参加多门课程,当学生的课程属性是List集合类型或者Map类型时,相关的配置如下代码所示:
<bean id="student" class="com.spring.beans.test.Student">
<property name="sno" value="101"></property>
<property name="sname" value="张三"></property>
<property name="course" >
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
<bean id="student" class="com.spring.beans.test.Student">
<property name="sno" value="101"></property>
<property name="sname" value="张三"></property>
<property name="course" >
<map>
<entry key="C#" value-ref="course1" />
<entry key="Java" value-ref="course2" />
</map>
</property>
</bean>
1.2 通过工厂方法配置
静态工厂方法:直接调用某一个类的静态方法,就可以返回bean的实例
public class StaticCourseFactory {
private static Map<String,Course> courses = new HashMap<String,Course>();
static{
courses.put("基础课", new Course("大学英语","Mr.E"));
courses.put("专业课", new Course("操作系统","Mr.C"));
}
//静态工厂方法
public static Course getCourse(String name){
return courses.get(name);
}
}
<!-- 通过静态工厂方法配置bean实例,class属性指向静态方法的全类名
factory-method:指向静态工厂方法的方法名,通过constructor-arg子标签传递参数值
-->
<bean id="course3" class="com.spring.beans.test.StaticCourseFactory" factory-method="getCourse">
<constructor-arg value="基础课"></constructor-arg> <!-- 传参数 -->
</bean>
实例工厂方法:首先配置工厂的实例,然后通过实例工厂方法来配置bean,factory-bean属性指向实例方法的bean,factory-method指向实例工厂方法的方法名,通过constructor-arg子标签传递参数值
<bean id="InstanceFactory" class="com.spring.beans.test.InstanceCourseFactory"></bean>
<bean id="course4" factory-bean="InstanceFactory" factory-method="getCourse">
<constructor-arg value="专业课"></constructor-arg>
</bean>
1.3 通过FactoryBean配置
定义一个类实现FactoryBean接口,重写相关的方法。在XML中进行bean配置(与全类名配置相似),返回的是FactoryBean中的getObject()方法。
二、基于注解配置Bean@Component:基本注解,标识一个受Spring管理的基本组件
@Controller:标识表现层的组件
@Service:标识业务层的组件
@Respository:标识持久层组件
以上注解有一个默认的属性value,可以用来标识IOC中的id。在组件类上使用特定的注解后,还需要在Spring的配置文件中声明<context:component-scan>
,其中base-package
属性指定要扫描的包及其子包,resource-pattern
属性是只扫描指定包的类。
@Component("course5")
public class Course {
private String cname;
private String tname;
public Course() {
}
...... //其他get、set部分代码省略
}
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="com.spring.beans.test"></context:component-scan>
</beans>
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-test.xml");
Course course = (Course) ctx.getBean("course5");
System.out.println(course);
}
}
其他几个注解的使用方法也是一样,只是在使用的地方(各个层)有区别。在使用<context:component-scan>
时,还有<context:exclude-filter>
和<context:include-filter>
等子标签,他们的作用分别是不包含指定组件和只包含指定组件,使用后者的时候要将父标签的use-default-filter的值设为false。