Spring IOC 容器

Spring IOC 容器

Ioc(Inversion of control) 控制反转
“控制”就是指对 对象的创建、维护、销毁等生命周期的控制,这个过程一般是由我们的程序去主动控制的,如使用new关键字去创建一个对象(创建),在使用过程中保持引用(维护),在失去全部引用后由GC去回收对象(销毁)。
“反转”就是指将对象的创建、维护、销毁等生命周期的控制由程序控制改为由IOC容器控制,需要某个对象时就直接通过名字去IOC容器中获取。

IOC的意义何在?
IOC并没有实现更多的功能,但它的存在使我们不需要很多代码、不需要考虑对象间复杂的耦合关系就能从IOC容器中获取合适的对象,而且提供了对 对象的可靠的管理,极大地降低了开发的复杂性。

Spring 提供两种不同类型的容器:

BeanFactory容器

由org.springframework.beans.factory.BeanFactory接口定义,为依赖注入(DI)提供支持。默认采用延迟初始化策略(lazy-load)。只用当客户端对象需要访问容器中的某个收管对象的时候,才对该收管对象进行初始化以及依赖注入操作。所以,相对来说,容器启动初期速度较快,所需要的资源有限。BeanFactory容器比较适用于资源有限,且功能要求不是本严格的场景。

下面我们通过一个具体的例子,来看看BeanFactory容器的应用:

使用IDEA或Eclipse创建一个Java Project,在src下建example包,然后创建HelloWorld.java,Main.java。另外在src下创建Bean.xml用来进行bean配置。

HelloWorld.java
1
2
3
4
5
6
7
8
9
10
11
12
package com.example;
public class HelloWorld {
private String message;

public void setMessage(String message) {
this.message = message;
}

public void getMessage() {
System.out.println("******" + message + "******");
}
}
Main.java
1
2
3
4
5
6
7
8
9
10
11
12
package com.example;

import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

public class MainApp {
public static void main(String[] args) {
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("Bean.xml"));
HelloWorld obj = (HelloWorld) factory.getBean("helloWorld");
obj.getMessage();
}
}
Bean.xml
1
2
3
4
5
6
7
8
9
10
11
12
<?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="com.example.HelloWorld">
<property name="message" value="Hello World!!!"/>
</bean>

</beans>

关于Bean和xml文件,在下面详细解释。这里主要理解BeanFactory容器的用法。运行Main.java方法之后,控制台将会出现

1
******Hello World!!!******

ApplicationContext 容器

ApplicationContext在BeanFactory的基础上构建,由 org.springframework.context.ApplicationContext 接口定义。是相对比较高级的容器实现,除了拥有BeanFactory的所有支持,ApplicationContext还提供了其他高级特性,比如事件发布、国际化信息支持等。ApplicationContext所管理的对象,在该类型容器启动之后,默认全部初始化并绑定完成。所以,相对于BeanFactory来说,ApplicationContext要求更多的系统资源,同时,因为在启动时就完成所有初始化,容器启动时间较之BeanFactory也会长一些。在那些系统资源充足,并且要求更多功能的场景中,ApplicationContext类型的容器是比较合适的选择。

下面我们将上面的BeanFactory容器的例子改为用ApplicationContext容器实现。

HelloWorld.java和Bean.xml这两个不需要改动,只需要将Main.java中的实现容器改一下即可。

Main.java
1
2
3
4
5
6
7
8
9
10
11
12
package com.example;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Bean.xml");
HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
obj.getMessage();
}
}

运行Main.java方法之后,控制台将会出现

1
******Hello World!!!******

Bean

Bean是被实例化的,组装的以及被Spring容器管理的Java对象。这些bean是由容器提供的配置元数据创建的。

bean的属性:

属性 描述
id Bean的唯一标识名,它必须是合法的XMLID,在整个XML文档中唯一。
Class 该属性是强制性的,用来指定创建bean的bean类
name 该属性用来指定唯一的bean标识符。在基于XML的配置元数组中,可以使用ID和/ 或者name属性来指定bean标识符。
scope 该属性用来指定由特定的bean定义创建的对象的作用域。
parent 子类Bean定义它所引用它的父类Bean。这时前面的class属性失效。子类Bean会继承父类Bean的所有属性,子类Bean也可以覆盖父类Bean的属性。注意:子类Bean和父类Bean是同一个Java类。
constructor-arg 用来注入依赖关系
autowiring mode 用来注入依赖关系
properties 用来注入依赖关系
lazy-initialzation mode 延迟初始化的bean告诉Ioc容器在它第一次被请求时,而不是在启动时去创建一个bean实例。
initialization 在bean的所有必须的属性被容器设置后,调用回调方法。
destruction 在包含该bean的容器被销毁时,使用回调方法。

Bean 的作用域

当在 Spring 中定义一个 bean 时,需要声明该 bean 的作用域的选项。例如,为了强制 Spring 在每次需要时都产生一个新的 bean 实例,你应该声明 bean 的作用域的属性为 prototype。同理,如果你想让 Spring 在每次需要时都返回同一个bean实例,你应该声明 bean 的作用域的属性为 singleton。

Spring 框架支持以下五个作用域,当使用 web-aware ApplicationContext 时,其中三个是可用的。

作用域 描述
singleton 在spring Ioc容器仅存在一个Bean实例,Bean以单例方式存在
prototype 每次从容器中调用Bean时,都返回一个新的实例
request 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
session 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean。仅适用于WebApplicationContext环境
global-session 一般用于Portlet应用环境, 该作用域仅适用于WebApplicationContext环境

bean的配置文件:

1
<?xml version="1.0" encoding="UTF-8"?>

指定版本号和编码方式

beans属性

1
2
3
4
5
6
7
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">

...

</beans>

beans:xml文件的根节点

xmlns:XML NameSpace的缩写,因为XML文件的标签名称都是自定义的,自己写的和其他人定义的标签很有可能会重复命名,而功能却不一样,所以需要加上一个namespace来区分这个xml文件和其他的xml文件,类似于java中的package。

xmlns:xsi :是指xml文件遵守xml规范,xsi全名:xml schema instance,是指具体用到的schema资源文件里定义的元素所准守的规范。即/spring-beans-2.0.xsd这个文件里定义的元素遵守什么标准。

xsi:schemaLocation:是指,本文档里的xml元素所遵守的规范,schemaLocation 属性用来引用(schema)模式文档,解析器可以在需要时使用这个文档对 XML 实例文档进行校验。它的值(URI)是成对出现的,第一个值表示命名空间,第二个值则表示描述该命名空间的模式文档的具体位置,两个值之间以空格分隔。

bean配置:

1
2
3
<bean id="helloWorld" class="com.example.HelloWorld">
<property name="message" value="Hello World!!!"/>
</bean>

id为Bean的名称,可以通过容器的getBean(“helloWorld”);来获取对应的Bean
class为HelloWorld类的全限定名(包名+类名)。

加上基本的属性即可。