IOC和DI概述
IOC其思想是反转资源获取的方向,传统的资源查找方式要求组件向容器发起请求查找资源。作为回应,容器适时的返回资源,而应用了IOC之后,则是容器主动地将资源推送给它所管理的组件,组件所要做的仅是选择一种合适的方式来接受资源,这种行为也被称为查找的被动形式。
DI是IOC的另一种表述方式,即**组件以一些预先定义好的方式(例如setter()
)接受来自容器的资源注入,相对于IOC而言,这种表述更直接。
配置Bean
在ApplicationContext.xml中配置bean
class
:bean的全类名,通过反射的方式在IOC容器中创建bean,所以要求bean中必须有无参数的构造器。
id
:标识容器中的bean,id唯一。
Spring容器
在SpringIOC容器读取bean配置创建bean实例之前,必须对它进行实例化,只有在容器实例化后,才可以从IOC容器里获取bean实例并使用。
Spring提供了两种类型的IOC容器实现
-
BeanFactory
:IOC容器的基本实现 -
ApplicationContext
:提供了更多的高级特性,是BeanFactory的子接口。
ClassPathXmlApplicationContext
是ApplicationContext
的一个实现类,其作用是从类路径下加载配置文件。
BeanFactory
是Spring框架的基础实施,面向Spring本身;ApplicationContext
面向使用Spring框架的开发者,几乎所有的应用场合都直接使用ApplicationContext而非底层的BeanFactory。但是无论使用何种方式,其配置文件都是相同的。
依赖注入
Spring支持3种依赖注入的方式
- 属性注入
- 构造器注入
- 工厂方法注入(很少使用)
属性注入
属性注入即通过setter()
注入Bean的属性值或依赖的对象
属性注入使用
元素,使用name
属性指定Bean的属性名称,value
属性或
子节点指定属性值。属性注入是实际应用中最常用的注入方式。
构造方法注入
通过构造方法注入Bean的属性值或依赖的对象,它保证了Bean实例在实例化后就可以使用。
构造器注入在
元素里声明属性,
中没有name属性
首先要有相应的构造器:
package com.spring.helloworld;
public class Car {
private String brand;
private String corp;
private int price;
private int maxSpeed;
public Car(String brand, String corp, int price) {
this.brand = brand;
this.corp = corp;
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", corp='" + corp + '\'' +
", price=" + price +
", maxSpeed=" + maxSpeed +
'}';
}
}
在ApplicationContext.xml文件中的构造方法注入:
Spring属性配置细节
字面值
可用字符串表示的值,可用通过
元素标签或value
属性进行注入。
基本数据类型及其封装类、String等类型都可以采取字面值注入的方式。若字面值中包含特殊字符,可用使用把字面值包裹起来。
引用其它Bean
组成应用程序的Bean经常需要相互协作以完成引用程序的功能,要使Bean能够相互访问,就必须在Bean配置文件中指定对Bean的引用。
在Bean的配置文件中,可以通过元素或
ref
属性来为Bean的属性或构造器参数指定对Bean的引用。
也可以在属性或构造器里包含Bean的声明,这样的Bean称为内部Bean。
我们先建立一个Person
类,如下:
package com.spring.helloworld;
public class Person {
private String name;
private int age;
private Car car;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", car=" + car +
'}';
}
}
在ApplicationContxt.xml文件中配置如下:
测试类:
package com.spring.helloworld;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
Person person = (Person) context.getBean("person");
System.out.println(person);
}
}
内部Bean
当Bean实例仅仅给一个特定的属性使用时,可以将其声明为内部Bean,内部Bean声明直接包含在
或
元素里,不需要设置任何id
或name
属性。
内部Bean不能使用在任何其他地方。
内部类的一个注入实例:
注入参数详解:null值和级联属性
可以使用专用的
元素标签为Bean的字符串或其他对象类型的属性注入null值。
和Struts、Hibernate等框架一样,Spring支持级联属性的配置。
集合属性
在Spring中可以通过一组内置的xml标签(例如:
,
,)来配置集合属性。
配置java.util.List
类型的属性,需要指定
标签,在标签里包含一些元素,这些标签可以通过
指定简单的常量值,通过指定对其他Bean的引用,通过
指定内置Bean定义,通过
指定空元素,甚至可以内嵌其他集合。
数组的定义和List一样,都使用
。
配置java.util.set需要使用
标签,定义元素的方法与List
一样。
示例:配置一个java.util.List
类型的属性。
- 我们在
com.spring.collection
包中新建一个Person
类:
package com.spring.collection;
import java.util.List;
public class Person {
private String name;
private int age;
private List car;
public List < Car > getCar() {
return car;
}
public void setCar(List < Car > car) {
this.car = car;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", car=" + car +
'}';
}
}
- 然后在
com.spring.collection
中新建一个Car
类:
package com.spring.collection;
public class Car {
private String brand;
private String corp;
private int price;
private int maxSpeed;
public void setBrand(String brand) {
this.brand = brand;
}
public void setCorp(String corp) {
this.corp = corp;
}
public void setPrice(int price) {
this.price = price;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
public Car(String brand, String corp, int price) {
this.brand = brand;
this.corp = corp;
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", corp='" + corp + '\'' +
", price=" + price +
", maxSpeed=" + maxSpeed +
'}';
}
}
- 在
applicationContext.xml
文件中的配置如下:
- 主函数如下:
package com.spring.collection;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) ctx.getBean("person2");
System.out.println(person);
}
}
使用节点来配置,
applicationContext.xml
文件部分代码:
使用
和
节点来为properties
属性赋值,applicationContext.xml
文件部分代码如下:
root
123
dataSource
类代码如下:
package com.spring.collection;
import java.util.Properties;
public class DataSource {
private Properties properties;
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "DataSource{" +
"properties=" + properties +
'}';
}
}
使用utility scheme定义集合
为了共享集合定义的Bean的引用,可以用util schema的集合标签定义独立的集合Bean。
applicationContext.xml
文件:
使用p命名空间
为了简化xml文件的配置,越来越多的xml文件采用属性而非子元素配置信息。
使用了p命名空间后,可以通过
元素属性的方式来配置Bean的属性。
例如: