IOC和DI概述
IOC其思想是反转资源获取的方向,传统的资源查找方式要求组件向容器发起请求查找资源。作为回应,容器适时的返回资源,而应用了IOC之后,则是容器主动地将资源推送给它所管理的组件,组件所要做的仅是选择一种合适的方式来接受资源,这种行为也被称为查找的被动形式。
DI是IOC的另一种表述方式,即组件以一些预先定义好的方式(例如setter()
)接受来自容器的资源注入,相对于IOC而言,这种表述更直接。
配置Bean
在ApplicationContext.xml中配置bean
<?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-->
<bean id="helloWorld" class="com.spring.helloworld.HelloWorld">
<!-- name为属性名-->
<property name="name" value="Spring"></property>
</bean>
</beans>
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的属性值或依赖的对象
属性注入使用<property>
元素,使用name
属性指定Bean的属性名称,value
属性或<value>
子节点指定属性值。属性注入是实际应用中最常用的注入方式。
<bean id="helloWorld" class="com.spring.helloworld.HelloWorld">
<!-- name为属性名-->
<property name="name" value="Spring"></property>
</bean>
构造方法注入
通过构造方法注入Bean的属性值或依赖的对象,它保证了Bean实例在实例化后就可以使用。
构造器注入在<constructor-arg>
元素里声明属性,<constructor-arg>
中没有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文件中的构造方法注入:
<!-- 通过构造器注入属性值可以指定参数的位置和参数的类型,以区分重载的构造器 -->
<bean id="car2" class="com.spring.helloworld.Car">
<constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
<constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
<constructor-arg value="300000" type="int"></constructor-arg>
</bean>
Spring属性配置细节
字面值
可用字符串表示的值,可用通过<value>
元素标签或value
属性进行注入。
基本数据类型及其封装类、String等类型都可以采取字面值注入的方式。若字面值中包含特殊字符,可用使用<![CDATA[]]>
把字面值包裹起来。
<bean id="car" class="com.spring.helloworld.Car">
<constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
<constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
<constructor-arg value="300000" type="int"></constructor-arg>
</bean>
引用其它Bean
组成应用程序的Bean经常需要相互协作以完成引用程序的功能,要使Bean能够相互访问,就必须在Bean配置文件中指定对Bean的引用。
在Bean的配置文件中,可以通过<ref>
元素或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文件中配置如下:
<bean id="person" class="com.spring.helloworld.Person">
<property name="name" value="Tom"></property>
<property name="age" value="24"></property>
<!-- 使用ref来建立bean之间的引用关系-->
<property name="car" ref="car2"></property>
</bean>
测试类:
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声明直接包含在<property>
或<constructor-arg>
元素里,不需要设置任何id
或name
属性。
内部Bean不能使用在任何其他地方。
内部类的一个注入实例:
<bean id="person" class="com.spring.helloworld.Person">
<property name="name" value="Tom"></property>
<property name="age" value="24"></property>
<!-- 内部bean-->
<property name="car">
<bean id="car3" class="com.spring.helloworld.Car">
<!-- 下面是使用构造方法注入,也可以使用属性注入的方式 -->
<constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
<constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
<constructor-arg value="300000111" type="int"></constructor-arg>
</bean>
</property>
</bean>
注入参数详解:null值和级联属性
可以使用专用的<null/>
元素标签为Bean的字符串或其他对象类型的属性注入null值。
和Struts、Hibernate等框架一样,Spring支持级联属性的配置。
<?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="car2" class="com.spring.helloworld.Car">
<constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
<constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
<constructor-arg value="300000" type="int"></constructor-arg>
</bean>
<bean id="person" class="com.spring.helloworld.Person">
<property name="name" value="Tom"></property>
<property name="age" value="24"></property>
<!-- 使用ref来建立bean之间的引用关系-->
<property name="car" ref="car2"></property>
<!-- 为级联属性赋值. 注意:属性需要先初始化后才可以为级联属性赋值,否则会有异常 -->
<property name="car.maxSpeed" value="25000"></property>
</bean>
</beans>
集合属性
在Spring中可以通过一组内置的xml标签(例如:<list>
,<set>
,<map>
)来配置集合属性。
配置java.util.List
类型的属性,需要指定<list>
标签,在标签里包含一些元素,这些标签可以通过<value>
指定简单的常量值,通过<ref>
指定对其他Bean的引用,通过<bean>
指定内置Bean定义,通过<null/>
指定空元素,甚至可以内嵌其他集合。
数组的定义和List一样,都使用<list>
。
配置java.util.set需要使用<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> 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
文件中的配置如下:
<?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="car4" class="com.spring.collection.Car">
<constructor-arg value="Audi1" type="java.lang.String"></constructor-arg>
<constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
<constructor-arg value="222" type="int"></constructor-arg>
</bean>
<bean id="car3" class="com.spring.collection.Car">
<constructor-arg value="Audi2" type="java.lang.String"></constructor-arg>
<constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
<constructor-arg value="111" type="int"></constructor-arg>
</bean>
<!-- 测试如何配置集合属性-->
<bean id="person2" class="com.spring.collection.Person">
<property name="age" value="27"></property>
<property name="name" value="Cerr"></property>
<property name="car" >
<!-- 使用list节点为list类型的属性赋值-->
<list>
<ref bean="car4" />
<ref bean="car3" />
</list>
</property>
</bean>
</beans>
- 主函数如下:
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);
}
}
使用<map>
节点来配置,applicationContext.xml
文件部分代码:
<!--配置Map属性值-->
<bean id="newPerson" class="com.spring.collection.NewPerson">
<property name="name" value="Rose"></property>
<property name="age" value="11"></property>
<property name="cars">
<map>
<entry key="AA" value-ref="car3"/>
<entry key="BB" value-ref="car4"/>
</map>
</property>
</bean>
使用<props>
和<prop>
节点来为properties
属性赋值,applicationContext.xml
文件部分代码如下:
<!-- 配置properties属性值-->
<bean id="dataSource" class="com.spring.collection.DataSource">
<property name="properties">
<props>
<prop key="user">root</prop>
<prop key="password">123</prop>
</props>
</property>
</bean>
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
文件:
<!-- 配置单例的集合Bean,以供多个bean进行引用 -->
<util:list id="cars1">
<ref bean="car3"/>
<ref bean="car4"/>
</util:list>
<bean id="person4" class="com.spring.collection.Person">
<property name="name" value="Jack"></property>
<property name="age" value="20"></property>
<property name="car" ref="cars1"></property>
</bean>
使用p命名空间
为了简化xml文件的配置,越来越多的xml文件采用属性而非子元素配置信息。
使用了p命名空间后,可以通过<bean>
元素属性的方式来配置Bean的属性。
例如:
<!-- 通过p命名空间为bean属性赋值,需要先导入p命名空间-->
<bean id="person5" class="com.spring.collection.Person" p:age="30" p:name="Queen" p:car-ref="cars1"></bean>