所谓 Bean 属性注入,简单点说就是将属性注入到 Bean 中的过程,而这属性既可以普通属性,也可以是一个对象(Bean)。
Spring 主要通过以下 2 种方式实现属性注入:
构造函数注入
setter 注入(又称设值注入)
构造函数注入
我们可以通过 Bean 的带参构造函数,以实现 Bean 的属性注入。
使用构造函数实现属性注入大致步骤如下:
在 Bean 中添加一个有参构造函数,构造函数内的每一个参数代表一个需要注入的属性;
在 Spring 的 XML 配置文件中,通过 及其子元素 对 Bean 进行定义;
在 元素内使用 元素,对构造函数内的属性进行赋值,Bean 的构造函数内有多少参数,就需要使用多少个 元素。
Grade类,使用Log记录信息:
package org.example;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Grade {
private static final Log LOGGER = LogFactory.getLog(Grade.class);
private Integer gradeId;
private String gradeName;
public Grade(Integer gradeId,String gradeName){
LOGGER.info("正在执行Grade的有参构造方法,参数分别为:gradeId="+gradeId+",gradeName="+gradeName);
this.gradeId = gradeId;
this.gradeName=gradeName;
}
@Override
public String toString() {
return "Grade{" +
"gradeId=" + gradeId +
", gradeName='" + gradeName + '\'' +
'}';
}
}
Student类
package org.example;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Student {
private static final Log LOGGER= LogFactory.getLog(Student.class);
private int id;
private String name;
private Grade grade;
public Student(int id,String name,Grade grade){
LOGGER.info("正在执行Student的有参构造方法,参数分别时:id="+id+",name="+",grade="+grade);
this.id =id;
this.name=name;
this.grade = grade;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", grade=" + grade +
'}';
}
}
Beans.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-3.0.xsd">
<bean id="helloWorld" class="org.example.HelloWorld">
<property name="message" value="Hello World!" />
</bean>
<bean id="grade" class="org.example.Grade">
<constructor-arg name="gradeId" value="1"></constructor-arg>
<constructor-arg name="gradeName" value="一年级"></constructor-arg>
</bean>
<bean id="student" class="org.example.Student">
<constructor-arg name="id" value="1"></constructor-arg>
<constructor-arg name="name" value="学生1"></constructor-arg>
<constructor-arg name="grade" ref="grade"></constructor-arg>
</bean>
</beans>
Mian类
public class Main {
private static final Log LOGGER = LogFactory.getLog(Main.class);
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
Student student = context.getBean("student",Student.class);
LOGGER.info(student.toString());
}
}
执行Main中的main()方法,控制台输出:
setter 注入
我们可以通过 Bean 的 setter 方法,将属性值注入到 Bean 的属性中。
在 Spring 实例化 Bean 的过程中,IoC 容器首先会调用默认的构造方法(无参构造方法)实例化 Bean(Java 对象),然后通过 Java 的反射机制调用这个 Bean 的 setXxx() 方法,将属性值注入到 Bean 中。
使用 setter 注入的方式进行属性注入,大致步骤如下:
在 Bean 中提供一个默认的无参构造函数(在没有其他带参构造函数的情况下,可省略),并为所有需要注入的属性提供一个 setXxx() 方法;
在 Spring 的 XML 配置文件中,使用 及其子元素 对 Bean 进行定义;
在 元素内使用 元素对各个属性进行赋值。
Student2类
package org.example;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Student2 {
private static final Log LOGGER = LogFactory.getLog(Student.class);
private int id;
private String name;
private Grade grade;
//无参构造方法,在没有其他带参构造方法的情况下,可以省略
public Student2() {
}
//id 属性的 setter 方法
public void setId(int id) {
LOGGER.info("正在执行 Student2 类的 setId() 方法…… ");
this.id = id;
}
//name 属性的 setter 方法
public void setName(String name) {
LOGGER.info("正在执行 Student2 类的 setName() 方法…… ");
this.name = name;
}
public void setGrade(Grade grade) {
LOGGER.info("正在执行 Student2 类的 setGrade() 方法…… ");
this.grade = grade;
}
@Override
public String toString() {
return "Student2{" +
"id=" + id +
", name='" + name + '\'' +
", grade=" + grade +
'}';
}
}
Grade2类
package org.example;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Grade2 {
private static final Log LOGGER = LogFactory.getLog(Grade.class);
private Integer gradeId;
private String gradeName;
/**
* 无参构造函数
* 若该类中不存在其他的带参构造函数,则这个默认的无参构造函数可以省略
*/
public Grade2() {
}
public void setGradeId(Integer gradeId) {
LOGGER.info("正在执行 Grade2 类的 setGradeId() 方法…… ");
this.gradeId = gradeId;
}
public void setGradeName(String gradeName) {
LOGGER.info("正在执行 Grade2 类的 setGradeName() 方法…… ");
this.gradeName = gradeName;
}
@Override
public String toString() {
return "Grade2{" +
"gradeId=" + gradeId +
", gradeName='" + gradeName + '\'' +
'}';
}
}
Beans.xml
<bean id="student2" class="org.example.Student2">
<!--使用 property 元素完成属性注入
name: 类中的属性名称,例如 id,name
value: 向属性注入的值 例如 学生的 id 为 1,name 为张三
-->
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="grade" ref="grade"></property>
</bean>
<bean id="grade2" class="org.example.Grade2">
<property name="gradeId" value="3"></property>
<property name="gradeName" value="三年级"></property>
</bean>
Main.java类
package org.example;
import com.sun.media.jfxmedia.logging.Logger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
private static final Log LOGGER = LogFactory.getLog(Main.class);
public static void main(String[] args) {
//
// ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
// HelloWorld obj = context.getBean("helloWorld",HelloWorld.class);
// System.out.println(obj.getMessage());
// BeanFactory factory = new ClassPathXmlApplicationContext("Beans.xml");
// HelloWorld obj = factory.getBean("helloWorld", HelloWorld.class);
// System.out.println(obj.getMessage());
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
// Student student = context.getBean("student",Student.class);
// LOGGER.info(student.toString());
Grade2 grade2 = context.getBean("grade2",Grade2.class);
LOGGER.info(grade2.toString());
}
}
运行结果:
短命名空间注入
我们在通过构造函数或 setter 方法进行属性注入时,通常是在 元素中嵌套 和 元素来实现的。这种方式虽然结构清晰,但书写较繁琐。
Spring 框架提供了 2 种短命名空间,可以简化 Spring 的 XML 配置,如下表。
短命名空间 | 简化的 XML 配置 | 说明 |
---|---|---|
p 命名空间 | 元素中嵌套的 property 元素 | 是 setter 方式属性注入的一种快捷实现方式 |
c 命名空间 | 元素中嵌套的 constructor元素 | 是构造函数属性注入的一种快捷实现方式 |
p 命名空间注入
p 命名空间是 setter 方式属性注入的一种快捷实现方式。通过它,我们能够以 bean 属性的形式实现 setter 方式的属性注入,而不再使用嵌套的 元素,以实现简化 Spring 的 XML 配置的目的。
首先我们需要在配置文件的 元素中导入以下 XML 约束。
xmls:p="htttp://www.springframework.org/schema/p"
在导入XML约束后,我们就会使用以下的形式及逆行属性注入
< bean id="Bean是唯一的标识“ class="包名+类名" p:普通属性=”普通属性值“ p:对象属性 ref="对象的引用">
使用 p 命名空间注入依赖时,必须注意以下 3 点:
Java 类中必须有 setter 方法;
Java 类中必须有无参构造器(类中不包含任何带参构造函数的情况,无参构造函数默认存在);
在使用 p 命名空间实现属性注入前,XML 配置的 元素内必须先导入 p 命名空间的 XML 约束。
实例:
Dept
package org.example;
public class Dept {
private String deptNo;
private String deptName;
public void setDeptNo(String deptNo){
this.deptName=deptName;
}
public void setDeptName(String deptName){
this.deptName=deptName;
}
@Override
public String toString() {
return "Dept{" +
"deptNo='" + deptNo + '\'' +
", deptName='" + deptName + '\'' +
'}';
}
}
Employee类
package org.example;
public class Employee {
private String empNo;
private String empName;
private Dept dept;
public String getEmpNo() {
return empNo;
}
public void setEmpNo(String empNo) {
this.empNo = empNo;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Employee{" +
"empNo='" + empNo + '\'' +
", empName='" + empName + '\'' +
", dept=" + dept +
'}';
}
}
Beans.xml
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="employee" class="org.example.Employee" p:empName="小李" p:dept-ref="dept" p:empNo="22222"></bean>
<bean id="dept" class="org.example.Dept" p:deptNo="1111" p:deptName="技术部"></bean>
</beans>
Main主类
package org.example;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
private static final Log LOGGER = LogFactory.getLog(Main.class);
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
Employee employee = context.getBean("employee",Employee.class);
LOGGER.info(employee.toString());
}
}
运行结果:
c 命名空间注入
c 命名空间是构造函数注入的一种快捷实现方式。通过它,我们能够以 属性的形式实现构造函数方式的属性注入,而不再使用嵌套的 元素,以实现简化 Spring 的 XML 配置的目的。
首先我们需要在配置文件的 元素中导入以下 XML 约束。
xmlns:c="http://www.springframework.org/schema/c"
在导入 XML 约束后,我们就能通过以下形式实现属性注入。
<bean id="Bean 唯一标志符" class="包名+类名" c:普通属性="普通属性值" c:对象属性-ref="对象的引用">
使用 c 命名空间注入依赖时,必须注意以下 2 点:
Java 类中必须包含对应的带参构造器;
在使用 c 命名空间实现属性注入前,XML 配置的 元素内必须先导入 c 命名空间的 XML 约束
Dept1
package org.example;
public class Dept1 {
//部门编号
private String deptNo;
//部门名称
private String deptName;
public Dept1(String deptNo, String deptName) {
this.deptNo = deptNo;
this.deptName = deptName;
}
@Override
public String toString() {
return "Dept{" +
"deptNo='" + deptNo + '\'' +
", deptName='" + deptName + '\'' +
'}';
}
}
Employee1
package org.example;
public class Employee1 {
//员工编号
private String empNo;
//员工姓名
private String empName;
//部门信息
private Dept1 dept1;
public Employee1(String empNo, String empName, Dept1 dept1) {
this.empNo = empNo;
this.empName = empName;
this.dept1 = dept1;
}
@Override
public String toString() {
return "Employee{" +
"empNo='" + empNo + '\'' +
", empName='" + empName + '\'' +
", dept=" + dept1 +
'}';
}
}
Beans,xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="employee1" class="org.example.Employee1" c:empName="小胡" c:dept1-ref="dept1" c:empNo="999"></bean>
<bean id="dept1" class="org.example.Dept1" c:deptNo="2222" c:deptName="测试部"></bean>
</beans>
Mian
package org.example;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
private static final Log LOGGER = LogFactory.getLog(Main.class);
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
Employee1 employee1 = context.getBean("employee1",Employee1.class);
LOGGER.info(employee1.toString());
}
}
运行结果