本节主要讲解在 Spring IoC 中的依赖注入(Dependency Injection)的两种实现方式。
由于英文水平有限,同时为保证原汁原味地表达Spring中关于依赖注入部分本来的含义,标题和部分内容采用 Spring Framework 官方文档中的英文原文。
另外,在测试代码中读取 Spring 配置文件时,尽量使用了完整的路径而未使用通配符。
0、Field and Proprey
设存在以下 Java Bean :
public class Person {
private int id ;
private String name ;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
在 Person 类中,以成员变量(Member Variable)形式存在的 id 和 name 属于 Person 类中的字段( Field )。字段(Field)本质上是一个变量,用于存储数值(可以是基本数据类型的数值、也可以是引用)。
在 Person 类中刻意声明了两种不同类型的字段(Field):
private int id ;
private String name ;
因为id是基本数据类型,因此该字段(Field)可以直接存储整数值。
而name是 String 类型,属于引用类型,因此该字段(Field)用于存储字符串的引用。
注意:即使在为 String 类型的变量赋值时使用了字符串字面量,也不能改变String变量中存储的是引用的事实。
在 Java Bean 中,字段(Field)通常是私有的,因此需要提供setter和getter来访问相应的字段,比如在 Person 类中,就有以下方法用以访问 id 字段:
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
在这里,我们要通过getter或setter来强调属性(property)的概念。
对于 getter 来说,按照以下顺序进行变换即可得到属性(property):
将 getId 方法的方法名去除 get ,得到 Id (注意不改变任何字母的大小写)
将 第1步 中得到的字符串首字母变小写,得到 id (即得到属性名称)
同样对于 setter 来说,也可以按照以下顺序进行变换即可得到属性(property):
将 setId 方法的方法名去除 set ,得到 Id (注意不改变任何字母的大小写)
将 第1步 中得到的字符串首字母变小写,得到 id (即得到属性名称)
因为绝大多数的 Java Bean 中字段(field)名称 和 属性(property) 是相同的,因此很多人会误以为属性(property)就是字段(field)、字段(field)就是属性(property)。
为了进一步区分字段(field)和属性(property),我们将 Person 改成以下形式:
public class Person {
private int personId ;
private String personName ;
public int getId() {
return personId;
}
public void setId(int id) {
this.personId = id;
}
public String getName() {
return personName;
}
public void setName(String name) {
this.personName = name;
}
}
此时,成员变量 personId 和 personName 是 Person 类中的字段(field),用于存储数据。而 id 和 name 是 Person 类的属性(property),用于访问相应的字段。
因此在 JSP 中,可以通过以下形式的 EL 表达式中可以用以下形式来获取属性(property)值
id : ${person.id}
name : ${person.name}
本质上,是通过 getId 和 getName 来获取 personId 和 personName 字段的值。
接下来,我们提供一个 Java Bean 供后续使用:
package io.malajava.ioc.injection;
import java.util.Date;
public class Sinaean {
private Integer id ;
private String name ;
private char gender ;
private Date birthdate ;
private boolean married ;
public Sinaean() {
super();
System.out.println( "public Sinaean()" );
}
public Sinaean(Integer id, String name) {
super();
System.out.println( "public Sinaean(Integer,String) : " + id );
this.id = id;
this.name = name;
}
public Sinaean(Integer id, String name, char gender) {
super();
System.out.println( "public Sinaean(Integer,String,char) : " + id );
this.id = id;
this.name = name;
this.gender = gender;
}
@Override
public String toString() {
return "{" +
"id : " + id +
", name : '" + name + '\'' +
", gender : " + gender +
", birthdate : [ " + birthdate +
" ], married : " + married +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
System.out.println( "Sinaean # setId( Integer )" );
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println( "Sinaean # setName( String )" );
this.name = name;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
System.out.println( "Sinaean # setGender( char )" );
this.gender = gender;
}
public Date getBirthdate() {
return birthdate;
}
public void setBirthdate(Date birthdate) {
System.out.println( "Sinaean # setBirthdate( java.util.Date )" );
this.birthdate = birthdate;
}
public boolean isMarried() {
return married;
}
public void setMarried(boolean married) {
System.out.println( "Sinaean # setMarried( boolean )" );
this.married = married;
}
}
1、Setter-based dependency injection
1.1、使用 标签实现注入
Java Bean
参见前面步骤中的 Sinaean 类
Configuration Metadata
注: 设以上内容存在于类路径下的 io/malajava/ioc/injection/injection-setter-property.xml 文件中。
注意,在以上配置中使用 标签可以为指定JavaBean的属性(property)注入属性值,其中:
标签的 name 属性用于指定 Java Bean 中属性的名称
标签的 value 属性用于指定 需要注入的属性值
标签的 ref 属性用于指定 引用其它的 bean
以下17种类型可以通过标签的 value 属性直接指定字面值:
Java语言中的 8 种基本数据类型
Java语言中 8 种基本数据类型对应的包装类类型
java.lang.String 类型
所有的引用类型(包括包装类类型和String类型)的属性,都可以使用 标签的 ref 属性来应用已经存在于IoC容器中的其它的 bean (同种类型),比如:
所有的引用类型(包括包装类类型和String类型)的属性,也都可以在标签内部使用 标签来创建需要注入的bean,比如:
Testing public class SetterInjectionTest1 {public static void main(String[] args) {
DateFormat df = new SimpleDateFormat( "yyyy-MM-dd" );
// 指定 Configuration Metadata
String configLocation = "classpath:io/malajava/ioc/injection/injection-setter-property.xml" ;
// 创建 Spring IoC 容器
ApplicationContext iocContainer = new ClassPathXmlApplicationContext( configLocation ) ;
// 从容器中获取 bean
Sinaean s = iocContainer.getBean( "xiaoyuer" , Sinaean.class );
System.out.println( s ); // s.toString()
System.out.println( df.format( s.getBirthdate() ) );
Sinaean x = iocContainer.getBean( "huawuque" , Sinaean.class );
System.out.println( x ); // x.toString()
System.out.println( df.format( x.getBirthdate() ) );
}
}
1.2、使用 p 命名空间 实现注入
Java Bean
参见前面步骤中的 Sinaean 类
Configuration Metadata
从 Spring 3 开始,支持在XML配置文件中使用 p 命名空间。
注: 设以上内容存在于类路径下的 io/malajava/ioc/injection/injection-setter-p-namespace.xml 文件中。
使用 p 命名空间时需要注意:
Java 语言中 8 种基本数据类型的属性可以直接在等号之后书写 字面值
8 种基本数据类型对应的包装类类型的属性可以直接在等号之后书写 字面值
java.lang.String 类型的属性可以直接在等号之后书写 字面值
所有引用类型(包括包装类类型和String类型)的属性都可以使用 -ref 来引用其它 bean
另外,千万要注意,只有在 标记中增加了以下内容才可以使用p命名空间:
xmlns:p="http://www.springframework.org/schema/p"
Tesging
public class SetterInjectionTest2 {
public static void main(String[] args) {
DateFormat df = new SimpleDateFormat( "yyyy-MM-dd" );
// 指定 Configuration Metadata
String configLocation = "classpath:io/malajava/ioc/injection/injection-setter-p-namespace.xml" ;
// 创建 Spring IoC 容器
ApplicationContext iocContainer = new ClassPathXmlApplicationContext( configLocation ) ;
// 从容器中获取 bean
Sinaean s = iocContainer.getBean( "huaan" , Sinaean.class );
System.out.println( s ); // s.toString()
System.out.println( df.format( s.getBirthdate() ) );
}
}
2、Constructor-based dependency injection
2.1、使用 标签实现参数注入
Java Bean
参见前面步骤中的 Sinaean 类
Configuration Metadata
设以下内容存在于类路径下的 io/malajava/ioc/injection/injection-constructor-arg.xml 文件中。
对于以下类型的参数来说,可以直接使用 Java 语言中 8 种基本数据类型 所有引用类型(包括包装类类型和String类型),也都可以在 实际应用时可以根据实际情况,灵活应用。 Testing } 添加后的 标签如下所示: 设以下内容存在于类路径下的 io/malajava/ioc/injection/injection-constructor-c.xml 文件中。 }
8 种基本数据类型对应的包装类类型
java.lang.String 类型
所有引用类型(包括包装类类型和String类型),都可以通过
public class ConstructorInjectionTest1 {public static void main(String[] args) {
// 指定 Configuration Metadata
String configLocation = "classpath:io/malajava/ioc/injection/injection-constructor-arg.xml" ;
// 创建 Spring IoC 容器
ApplicationContext iocContainer = new ClassPathXmlApplicationContext( configLocation ) ;
Sinaean s = null ;
// 从容器中获取 bean
s = iocContainer.getBean( "first" , Sinaean.class );
System.out.println( s ); // s.toString()
s = iocContainer.getBean( "second" , Sinaean.class );
System.out.println( s ); // s.toString()
s = iocContainer.getBean( "third" , Sinaean.class );
System.out.println( s ); // s.toString()
s = iocContainer.getBean( "fourth" , Sinaean.class );
System.out.println( s ); // s.toString()
}
2.2、使用 c 命名空间 实现参数注入
Java Bean
参见前面步骤中的 Sinaean 类
Configuration Metadata
在 Spring 配置文件中通过添加以下内容来使用 c 命名空间: xmlns:c="http://www.springframework.org/schema/c"
Testing public class ConstructorInjectionTest2 {
public static void main(String[] args) {
// 指定 Configuration Metadata
String configLocation = "classpath:io/malajava/ioc/injection/injection-constructor-c.xml" ;
// 创建 Spring IoC 容器
ApplicationContext iocContainer = new ClassPathXmlApplicationContext( configLocation ) ;
Sinaean s = null ;
// 从容器中获取 bean
s = iocContainer.getBean( "first" , Sinaean.class );
System.out.println( s ); // s.toString()
s = iocContainer.getBean( "second" , Sinaean.class );
System.out.println( s ); // s.toString()
s = iocContainer.getBean( "third" , Sinaean.class );
System.out.println( s ); // s.toString()
s = iocContainer.getBean( "fourth" , Sinaean.class );
System.out.println( s ); // s.toString()
}
© 著作权归作者所有