2.2.1 IoC容器的概念
IoC容器就是具有依赖注入功能的容器,IoC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。应用程序无需直接在代码中new相关的对象。应用程序由IoC容器进行组装。在Spring中BeanFactory是IoC容器的实际代表者。
Spring IoC容器是如何知道哪些是它管理的对象呢?这就需要配置文件,Spring IoC容器通过读取配置文件中的配置元数据,通过元数据对应用中的各个对象进行实例化及装配。一般使用基于xml配置文件进行配置元数据,而且Spring与配置文件完全解耦,可以使用其他任何可能的方式进行配置元数据,比如注解,基于java文件的,基于属性文件的配置都可以。
那Spring IoC容器管理的对象叫什么呢?
2.2.2 Bean的概念
由IoC容器管理的那些组成你应用程序的对象我们就叫它Bean,Bean就是由Spring 容器初始化、装配及管理的对象,除此之外,bean就与应用程序中的其他对象没有什么区别了。那IoC怎样确定如何实例化Bean,管理Bean之间的依赖关系以及管理Bean呢?这就需要配置元数据,在Spring中由BeanDefinition代表,后边会有详细介绍,配置元数据指定如何实例化Bean,如何组装Bean等。概念知道的差不多了,让我们来做个简单的例子。
2.2.3 Hello World
一、配置环境:
JDK安装:安装最新的JDK,至少需要Java1.5及以上。
开发工具:我们使用的是EclipseIDE for Java (eclipse-jee-helios-SR2)。
Spring依赖:Spring-framework-3.2.4.RELEASE
下载地址:http://repo.spring.io/release/org/springframework/spring/
二、开始Spring Hello World之旅
1.准备所需的jar包:
核心jar包:
spring-core-3.2.4.RELEASE.jar
spring-beans-3.2.4.RELEASE.jar
spring-context-3.2.4.RELEASE.jar
spring-expression-3.2.4.RELEASE.jar
依赖的jar包:
commons-logging-1.2.jar
log4j-1.2.17.jar
2.创建标准Java工程:
1)创建项目,名称为:spring_helloworld
2) 添加spring所需jar包和Junit4
3)项目搭建好了,让我们来开发接口,此处我们只需实现打印“Hello World”,所有我们定义一个“sayHello”接口,代码如下:
package com.gaoyinghao.spring.helloworld.service;
public interface IHelloWorldService {
public void sayHelloWorld();
}
4)接口开发好了,让我们通过实现接口来完成打印“Hello World!”功能。
<pre name="code" class="java">package com.gaoyinghao.spring.helloworld.service.impl;
importcom.gaoyinghao.spring.helloworld.service.IHelloWorldService;
public class HelloWorldServiceImpl implements IHelloWorldService{
@Override
public void sayHelloWorld() {
System.out.println("HelloWorld!");
}
}
5)接口和实现都开发好了,那如何使用Spring IoC容器来管理他们呢?这就需要配置文件,让IoC容器知道要管理哪些对象,让我们来配置文件helloworld.xml(放到sources目录下)
<?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">
<!-- id表示这个组件的名字,class表示组件类 -->
<bean id="helloWorldService" class="com.gaoyinghao.spring.helloworld.service.impl.HelloWorldServiceImpl"></bean>
</beans>
6)现在万事具备,那如何获取IoC容器并完成我们所需要的功能呢?首先应该实例化一个IoC容器,然后从容器中获取需要的对象,然后调用接口完成我们需要的功能,代码示例如下:
package com.gaoyinghao.spring.helloworld.service;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
importorg.springframework.context.support.ClassPathXmlApplicationContext;
public class IHelloWorldServiceTest {
@Test
public void testSayHelloWorld() {
//1、读取配置文件实例化一个IoC容器
ApplicationContext context = new ClassPathXmlApplicationContext("helloworld.xml");
//2、从容器中获取Bean,注意此处完全“面向接口编程,而不是面向实现”
IHelloWorldService helloWorldService = context.getBean("helloWorldService",IHelloWorldService.class);
//3、执行业务逻辑
helloWorldService.sayHelloWorld();
}
}
7)自此一个完整的SpringHello World已完成,是不是很简单,让我们深入理解下容器和Bean吧。
2.2.4 详解IoC容器
在Spring 中,IoC容器的代表就是org.springframework.beans包中的BeanFactory接口,BeanFactory接口提供了IoC容器最基本功能,而org.springframework.context包下的ApplicationContext接口扩展了BeanFactory,还提供了与SpringAOP集成,国际化处理,事件传播及提供不同层次的context实现(如针对web应用的WebApplicationContext)。简单说,BeanFactory提供了IoC容器最基本功能,而ApplicationContext则增加了更多支持企业级功能支持。ApplicationContext完全继承了BeanFactory,因而BeanFactory所具有的语义也适用于ApplicationContext。
容器实现一览:
XmlBeanFactory:BeanFactory实现,提供基本的IoC容器功能,可以从classpath或文件系统等获取资源:
(1) File file = new File(“beanx.xml”);
Resource resource = new FileSystemResource(file);
BeanFactory beanFactory = new XmlBeanFactory(resource);
(2) Resource resource = newClassPathResource(“classpath.xml”);
BeanFactory beanFactory = newXmlBeanFactory(resource);
ClasspathXmlApplicationContext:ApplicationContext实现,从classpath获取配置资源;
BeanFactorybeanFactory = new ClassPathXmlApplicationContext(“classpath.xml”);
FileSystemXmlApplicationContext:ApplicationContext实现,从文件系统获取资源文件;
BeanFactorybeanFactory = new FileSystemXmlApplicationContext(“fileSystemConfig.xml”);
ApplicationContext接口获取Bean方法简介:
Object getBean(String name):根据名称返回一个Bean,客户端需要自己进行类型转换;
T getBean(String name,Class<T>requiredType):根据名称和指定的类型返回一个Bean,客户端无需自己进行类型转换,如果类型转换失败,容器抛出异常。
T getBean(Class<T> requiredType):根据指定的类型返回一个Bean,客户端无需自己进行类型转换,如果没有或有多于一个Bean存在容器将抛出异常。
Map<String,T>getBeansOfType(Class<T> type):根据指定的类型返回一个键为名字和值为Bean对象的Map,如果没有Bean对象存在,则返回空的Map。
让我们来看下IoC容器到底是如何工作的。在此我们以xml配置方式来分析一下:
一、准备配置文件:就像前边HelloWorld配置文件一样,在配置文件中声明Bean定义,也就是为Bean配置元数据。
二、由IoC容器进行解析元数据:IoC容器的BeanReader读取并解析配置文件,根据定义生成BeanDefinition配置元数据对象,IoC容器根据BeanDefinition进行实例化,配置及组装Bean。
三、实例化IoC容器:由客户端实例化容器,获取需要的Bean。
整个过程是不是很简单,执行过程如下图,其实IoC容器很容易使用,主要是如何进行Bean定义。
2.2.5 小结
除了测试程序代码外,也就是程序入口,所有代码都没有出现Spring任何组件,而且所有我们写的代码没有实现框架拥有的接口,因而能非常容易的替换掉Spring,是不是非入侵。
客户端代码完全面向接口编程,无需知道实现类,可以通过修改配置文件来更换接口实现,客户端代码不需要任何修改,是不是低耦合。
如果在开发初期没有真正的实现,我们可以模拟一个实现来测试,不耦合代码,是不是很方便测试。
Bean之间几乎没有依赖关系,是不是很容易重用。