1.Spring Bean属性注入的几种方式
1.1构造函数注入
使用构造函数实现属性注入大致步骤如下:
- 在 Bean 中添加一个有参构造函数,构造函数内的每一个参数代表一个需要注入的属性;
- 在 Spring 的 XML 配置文件中,通过 <beans> 及其子元素 <bean> 对 Bean 进行定义;
- 在 <bean> 元素内使用 <constructor-arg> 元素,对构造函数内的属性进行赋值,Bean 的构造函数内有多少参数,就需要使用多少个 <constructor-arg> 元素。
示例如下:
Grade(Bean)类代码如下:
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("正在执行 Course 的有参构造方法,参数分别为:gradeId=" + gradeId + ",gradeName=" + gradeName);
this.gradeId = gradeId;
this.gradeName = gradeName;
}
@Override
public String toString() {
return "Grade{" +
"gradeId=" + gradeId +
", gradeName='" + gradeName + '\'' +
'}';
}
}
Student(Bean)类代码如下:
这里可以说Student类依赖于Grade类。
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("正在执行 Course 的有参构造方法,参数分别为:id=" + id + ",name=" + 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代码如下:
注意直接类型用value,自定义的引用类型用ref。
<?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="student" class="net.biancheng.c.Student">
<constructor-arg name="id" value="2"></constructor-arg>
<constructor-arg name="name" value="李四"></constructor-arg>
<constructor-arg name="grade" ref="grade"></constructor-arg>
</bean>
<bean id="grade" class="net.biancheng.c.Grade">
<constructor-arg name="gradeId" value="4"></constructor-arg>
<constructor-arg name="gradeName" value="四年级"></constructor-arg>
</bean>
</beans>
主类代码如下:
public class MainApp {
private static final Log LOGGER = LogFactory.getLog(MainApp.class);
public static void main(String[] args) {
//获取 ApplicationContext 容器
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
//获取名为 student 的 Bean
Student student = context.getBean("student", Student.class);
//通过日志打印学生信息
LOGGER.info(student.toString());
}
}
控制台输出如下:
十二月 16, 2021 4:38:42 下午 net.biancheng.c.Grade <init>
信息: 正在执行 Course 的有参构造方法,参数分别为:gradeId=4,gradeName=四年级
十二月 16, 2021 4:38:42 下午 net.biancheng.c.Student <init>
信息: 正在执行 Course 的有参构造方法,参数分别为:id=2,name=李四,grade=Grade{gradeId=4, gradeName='四年级'}
十二月 16, 2021 4:38:42 下午 net.biancheng.c.MainApp main
信息: Student{id=2, name='李四', grade=Grade{gradeId=4, gradeName='四年级'}}
1.2 setter注入
使用 setter 注入的方式进行属性注入,大致步骤如下:
- 在 Bean 中提供一个默认的无参构造函数(在没有其他带参构造函数的情况下,可省略),并为所有需要注入的属性提供一个 setXxx() 方法;
- 在 Spring 的 XML 配置文件中,使用 <beans> 及其子元素 <bean> 对 Bean 进行定义;
- 在 <bean> 元素内使用 <property> 元素对各个属性进行赋值。
示例如下:
Student(Bean)类代码如下:
public class Student {
private static final Log LOGGER = LogFactory.getLog(Student.class);
private int id;
private String name;
private Grade grade;
//无参构造方法,在没有其他带参构造方法的情况下,可以省略
public Student() {
}
//id 属性的 setter 方法
public void setId(int id) {
LOGGER.info("正在执行 Student 类的 setId() 方法…… ");
this.id = id;
}
//name 属性的 setter 方法
public void setName(String name) {
LOGGER.info("正在执行 Student 类的 setName() 方法…… ");
this.name = name;
}
public void setGrade(Grade grade) {
LOGGER.info("正在执行 Student 类的 setGrade() 方法…… ");
this.grade = grade;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", grade=" + grade +
'}';
}
}
Grade(Bean)类代码如下:
public class Grade {
private static final Log LOGGER = LogFactory.getLog(Grade.class);
private Integer gradeId;
private String gradeName;
/**
* 无参构造函数
* 若该类中不存在其他的带参构造函数,则这个默认的无参构造函数可以省略
*/
public Grade() {
}
public void setGradeId(Integer gradeId) {
LOGGER.info("正在执行 Grade 类的 setGradeId() 方法…… ");
this.gradeId = gradeId;
}
public void setGradeName(String gradeName) {
LOGGER.info("正在执行 Grade 类的 setGradeName() 方法…… ");
this.gradeName = gradeName;
}
@Override
public String toString() {
return "Grade{" +
"gradeId=" + gradeId +
", gradeName='" + gradeName + '\'' +
'}';
}
}
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="student" class="net.biancheng.c.Student">
<!--使用 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="grade" class="net.biancheng.c.Grade">
<property name="gradeId" value="3"></property>
<property name="gradeName" value="三年级"></property>
</bean>
</beans>
Main方法如上,输出信息一致。
1.3 短命名空间注入
本质上是对前两种方法的一个简写形式。
我们在通过构造函数或 setter 方法进行属性注入时,通常是在 <bean> 元素中嵌套 <property> 和 <constructor-arg> 元素来实现的。这种方式虽然结构清晰,但书写较繁琐。
Spring 框架提供了 2 种短命名空间,可以简化 Spring 的 XML 配置,如下表。
p命名空间注入
p 命名空间是 setter 方式属性注入的一种快捷实现方式。通过它,我们能够以 bean 属性的形式实现 setter 方式的属性注入,而不再使用嵌套的 <property> 元素,以实现简化 Spring 的 XML 配置的目的。
首先我们需要在配置文件的 <beans> 元素中导入以下 XML 约束。
xmlns:p="http://www.springframework.org/schema/p"
在导入 XML 约束后,我们就能通过以下形式实现属性注入。
<bean id="Bean 唯一标志符" class="包名+类名" p:普通属性="普通属性值" p:对象属性-ref="对象的引用">
Bean类省略了,看一下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="net.biancheng.c.Employee" p:empName="小李" p:dept-ref="dept" p:empNo="22222"></bean>
<bean id="dept" class="net.biancheng.c.Dept" p:deptNo="1111" p:deptName="技术部"></bean>
</beans>
c命名空间注入
c 命名空间是构造函数注入的一种快捷实现方式。通过它,我们能够以 <bean> 属性的形式实现构造函数方式的属性注入,而不再使用嵌套的 <constructor-arg> 元素,以实现简化 Spring 的 XML 配置的目的。
首先我们需要在配置文件的 <beans> 元素中导入以下 XML 约束。
xmlns:c="http://www.springframework.org/schema/c"
在导入 XML 约束后,我们就能通过以下形式实现属性注入。
<bean id="Bean 唯一标志符" class="包名+类名" c:普通属性="普通属性值" c:对象属性-ref="对象的引用">
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="employee" class="net.biancheng.c.Employee" c:empName="小胡" c:dept-ref="dept" c:empNo="999"></bean>
<bean id="dept" class="net.biancheng.c.Dept" c:deptNo="2222" c:deptName="测试部"></bean>
</beans>
2.Spring注入内部Beans
之前我们在处理类的依赖时(也就是一个类中保持有另外一个类的对象),使用的是ref属性进行链接到依赖类的id,我们还可以使用内部注入的方式来完成依赖注入。
来看一个代码示例:
TextEditor类代码文件(Bean):
public class TextEditor {
private SpellChecker spellChecker;
// a setter method to inject the dependency.
public void setSpellChecker(SpellChecker spellChecker) {
System.out.println("Inside setSpellChecker." );
this.spellChecker = spellChecker;
}
// a getter method to return spellChecker
public SpellChecker getSpellChecker() {
return spellChecker;
}
public void spellCheck() {
spellChecker.checkSpelling();
}
}
下面是另一个依赖的类文件 SpellChecker.java 内容:
public class SpellChecker {
public SpellChecker(){
System.out.println("Inside SpellChecker constructor." );
}
public void checkSpelling(){
System.out.println("Inside checkSpelling." );
}
}
主文件内容如下:
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
TextEditor te = (TextEditor) context.getBean("textEditor");
te.spellCheck();
}
}
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">
<!-- Definition for textEditor bean using inner bean -->
<bean id="textEditor" class="com.tutorialspoint.TextEditor">
<property name="spellChecker">
<bean id="spellChecker" class="com.tutorialspoint.SpellChecker"/>
</property>
</bean>
3.Spring注入集合
你已经看到了如何使用 value 属性来配置基本数据类型和在你的 bean 配置文件中使用<property>
标签的 ref 属性来配置对象引用。这两种情况下处理奇异值传递给一个 bean。
现在如果你想传递多个值,如 Java Collection 类型 List、Set、Map 和 Properties,应该怎么做呢。
示例如下:
这里是 JavaCollection.java 文件的内容:
public class JavaCollection {
List addressList;
Set addressSet;
Map addressMap;
Properties addressProp;
public void setAddressList(List addressList) {
this.addressList = addressList;
}
public List getAddressList() {
System.out.println("List Elements :" + addressList);
return addressList;
}
public void setAddressSet(Set addressSet) {
this.addressSet = addressSet;
}
public Set getAddressSet() {
System.out.println("Set Elements :" + addressSet);
return addressSet;
}
public void setAddressMap(Map addressMap) {
this.addressMap = addressMap;
}
public Map getAddressMap() {
System.out.println("Map Elements :" + addressMap);
return addressMap;
}
public void setAddressProp(Properties addressProp) {
this.addressProp = addressProp;
}
public Properties getAddressProp() {
System.out.println("Property Elements :" + addressProp);
return addressProp;
}
}
主方法内容:
public class MainApp {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("Beans.xml");
JavaCollection jc=(JavaCollection)context.getBean("javaCollection");
jc.getAddressList();
jc.getAddressSet();
jc.getAddressMap();
jc.getAddressProp();
}
}
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">
<!-- Definition for javaCollection -->
<bean id="javaCollection" class="com.tutorialspoint.JavaCollection">
<!-- results in a setAddressList(java.util.List) call -->
<property name="addressList">
<list>
<value>INDIA</value>
<value>Pakistan</value>
<value>USA</value>
<value>USA</value>
</list>
</property>
<!-- results in a setAddressSet(java.util.Set) call -->
<property name="addressSet">
<set>
<value>INDIA</value>
<value>Pakistan</value>
<value>USA</value>
<value>USA</value>
</set>
</property>
<!-- results in a setAddressMap(java.util.Map) call -->
<property name="addressMap">
<map>
<entry key="1" value="INDIA"/>
<entry key="2" value="Pakistan"/>
<entry key="3" value="USA"/>
<entry key="4" value="USA"/>
</map>
</property>
<!-- results in a setAddressProp(java.util.Properties) call -->
<property name="addressProp">
<props>
<prop key="one">INDIA</prop>
<prop key="two">Pakistan</prop>
<prop key="three">USA</prop>
<prop key="four">USA</prop>
</props>
</property>
</bean>
</beans>
上面注入的都是基本元素,如果集合中存储的是引用类型元素应该如何写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 Definition to handle references and values -->
<bean id="..." class="...">
<!-- Passing bean reference for java.util.List -->
<property name="addressList">
<list>
<ref bean="address1"/>
<ref bean="address2"/>
<value>Pakistan</value>
</list>
</property>
<!-- Passing bean reference for java.util.Set -->
<property name="addressSet">
<set>
<ref bean="address1"/>
<ref bean="address2"/>
<value>Pakistan</value>
</set>
</property>
<!-- Passing bean reference for java.util.Map -->
<property name="addressMap">
<map>
<entry key="one" value="INDIA"/>
<entry key ="two" value-ref="address1"/>
<entry key ="three" value-ref="address2"/>
</map>
</property>
</bean>
</beans>