Spring Ioc (Inversion of Control)

如下整理自http://jinnianshilongnian.iteye.com/blog/1413846,若有侵权当即删除。

Iochtml

Ioc(Inversion of Control),即控制反转。不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。 传统Java SE程序设计,咱们直接在对象内部经过new进行建立对象,是程序主动去建立依赖对象;而IoC是有专门一个容器来建立这些对象,即由Ioc容器来控制对象的建立;IoC 容器控制了对象(主要控制了外部资源获取,不仅是对象包括好比文件等)。
传统应用程序是由咱们本身在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙建立及注入依赖对象;为什么是反转?由于由容器帮咱们查找及注入依赖对象,对象只是被动的接受依赖对象,因此是反转;哪些方面反转了?依赖对象的获取被反转了。

Ioc 容器java

IoC容器就是具备依赖注入功能的容器,IoC容器负责实例化、定位、配置应用程序中的对象及创建这些对象间的依赖。应用程序无需直接在代码中new相关的对象,应用程序由IoC容器进行组装。在Spring中BeanFactory是IoC容器的实际表明者web

Spring IoC容器如何知道哪些是它管理的对象呢?这就须要配置文件,Spring IoC容器经过读取配置文件中的配置元数据,经过元数据对应用中的各个对象进行实例化及装配。通常使用基于xml配置文件进行配置元数据,并且Spring与配置文件彻底解耦的,可使用其余任何可能的方式进行配置元数据,好比注解、基于java文件的、基于属性文件的配置均可以。

Spring Ioc容器的表明就是org.springframework.beans包中的BeanFactory接口,BeanFactory接口提供了IoC容器最基本功能;而org.springframework.context包下的ApplicationContext接口扩展了BeanFactory,还提供了与Spring AOP集成、国际化处理、事件传播及提供不一样层次的context实现 (如针对web应用的WebApplicationContext)。简单说, BeanFactory提供了IoC容器最基本功能,而 ApplicationContext 则增长了更多支持企业级功能支持。ApplicationContext彻底继承BeanFactory,于是BeanFactory所具备的语义也适用于ApplicationContext。

容器实现一览:

• XmlBeanFactory:BeanFactory实现,提供基本的IoC容器功能,能够从classpath或文件系统等获取资源;
(1) File file = new File("fileSystemConfig.xml");
Resource resource = new FileSystemResource(file);
BeanFactory beanFactory = new XmlBeanFactory(resource);spring

(2)Resource resource = new ClassPathResource("classpath.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
Deprecated. as of Spring 3.1 in favor of DefaultListableBeanFactory and XmlBeanDefinitionReader编程

• ClassPathXmlApplicationContext:ApplicationContext实现,从classpath获取配置文件;
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath.xml");数组

• FileSystemXmlApplicationContext:ApplicationContext实现,从文件系统获取配置文件。
BeanFactory beanFactory = new FileSystemXmlApplicationContext("fileSystemConfig.xml");
ide

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。

示例:
项目结构图,注意fileSystemConfig.xml的位置。用于文件系统配置的读取
QQ20120731010934_thumb5ui

HelloApi.java和HelloImpl.java是一个简单的接口及其实现,打印一句Hello World!,bean.xml和fileSystemConfig.xml内容相同,都只有一句简单的对bean的配置:<bean id="hello" class="cn.nevo.service.impl.HelloImpl"></bean>

测试代码演示了使用不一样的Ioc容器实现去读取类路径配置文件和文件系统文件的方式:
this

public class HelloServiceTest {

	@SuppressWarnings("deprecation")
	@Test
	public void testXmlBeanFactoryBaseOnFileSystem() {
		// 1.准备配置文件,从文件系统获取配置文件,默认是相对路径,能够指定绝对路径
		File file = new File("fileSystemConfig.xml");
		Resource resource = new FileSystemResource(file);
		// 2.初始化容器
		BeanFactory beanFactory = new XmlBeanFactory(resource);
		// 二、从容器中获取Bean
		HelloApi helloApi = beanFactory.getBean("hello", HelloApi.class);
		// 三、执行业务逻辑
		helloApi.sayHello();
	}

	@SuppressWarnings("deprecation")
	@Test
	public void testXmlBeanFactoryBaseOnClassPath() {
		// 1.准备配置文件,从当前类加载路径中获取配置文件
		Resource resource = new ClassPathResource("bean.xml");
		// 2.初始化容器
		BeanFactory beanFactory = new XmlBeanFactory(resource);
		// 二、从容器中获取Bean
		HelloApi helloApi = beanFactory.getBean("hello", HelloApi.class);
		// 三、执行业务逻辑
		helloApi.sayHello();
	}

	@Test
	public void testClassPathXmlApplicationContextBaseOnClassPath() {
		// 1.准备配置文件,从当前类加载路径中获取配置文件
		// 2.初始化容器
		BeanFactory beanFactory = new ClassPathXmlApplicationContext("bean.xml");
		// 二、从容器中获取Bean
		HelloApi helloApi = beanFactory.getBean("hello", HelloApi.class);
		// 三、执行业务逻辑
		helloApi.sayHello();
	}

	@Test
	public void testFileSystemApplicationContextBaseOnFileSystem() {
		// 1.准备配置文件,从文件系统获取配置文件,默认是相对路径,能够指定绝对路径
		// 2.初始化容器
		BeanFactory beanFactory = new FileSystemXmlApplicationContext(
				"fileSystemConfig.xml");
		// 二、从容器中获取Bean
		HelloApi helloApi = beanFactory.getBean("hello", HelloApi.class);
		// 三、执行业务逻辑
		helloApi.sayHello();
	}
}

IoC容器究竟是如何工做。在此咱们以xml配置方式来分析一下:
1、准备配置文件:在配置文件中声明Bean定义也就是为Bean配置元数据。
2、由IoC容器进行解析元数据: IoC容器的Bean Reader读取并解析配置文件,根据定义生成BeanDefinition配置元数据对象,IoC容器根据BeanDefinition进行实例化、配置及组装Bean。
3、实例化IoC容器:也就是实例化BeanFactory的各类实现,由客户端实例化容器,获取须要的Bean。

XML配置文件的结构

<beans>  
    <import resource=”resource1.xml”/>  
    <bean id=”bean1”class=””></bean>  
    <bean id=”bean2”class=””></bean>  
    <bean name=”bean2”class=””></bean>  
    <alias alias="bean3" name="bean2"/>  
    <import resource=”resource2.xml”/>  
</beans>

一、<bean>标签主要用来进行Bean定义;
二、alias用于定义Bean别名的;
三、import用于导入其余配置文件的Bean定义,这是为了加载多个配置文件,固然也能够把这些配置文件构造为一个数组(new String[] {“config1.xml”, config2.xml})传给ApplicationContext实现进行加载多个配置文件,那一个更适合由用户决定;这两种方式都是经过调用Bean Definition Reader 读取Bean定义,内部实现没有任何区别。<import>标签能够放在<beans>下的任何位置,没有顺序关系。

Bean

由IoC容器管理的那些组成你应用程序的对象咱们就叫它Bean, Bean就是由Spring容器初始化、装配及管理的对象,除此以外,bean就与应用程序中的其余对象没有什么区别了。那IoC怎样肯定如何实例化Bean、管理Bean之间的依赖关系以及管理Bean呢?这就须要配置元数据,在Spring中由BeanDefinition表明,后边会详细介绍,配置元数据指定如何实例化Bean、如何组装Bean等。

Bean的配置

Spring IoC容器目的就是管理Bean,这些Bean将根据配置文件中的Bean定义进行建立,而Bean定义在容器内部由BeanDefinition对象表示,该定义主要包含如下信息:
全限定类名(FQN):用于定义Bean的实现类;
Bean行为定义:这些定义了Bean在容器中的行为;包括做用域(单例、原型建立)、是否惰性初始化及生命周期等;
Bean建立方式定义:说明是经过构造器仍是工厂方法建立Bean;
Bean之间关系定义:即对其余bean的引用,也就是依赖关系定义,这些引用bean也能够称之为同事bean 或依赖bean,也就是依赖注入。

Bean定义只有“全限定类名”在当使用构造器或静态工厂方法进行实例化bean时是必须的,其余都是可选的定义。难道Spring只能经过配置方式来建立Bean吗?回答固然不是,某些SingletonBeanRegistry接口实现类实现也容许将那些非BeanFactory建立的、已有的用户对象注册到容器中,这些对象必须是共享的,好比使用DefaultListableBeanFactory 的registerSingleton() 方法。不过建议采用元数据定义。

BeanDefinition

spring能够经过xml配置文件定义bean,beanFactory能够建立、查找配置文件中定义的这些bean,spring内部是如何将配置文件中所定义的bean变成可让beanFactory建立与管理的呢?这是依靠BeanDefinition进行实现。BeanDefinition是一个接口,它描述了一个bean的实例,保存了bean的定义信息,是bean在内存中的描述形式。xml配置文件所定义的每一个bean在内存中都有对应的Bedifinition对象进行描述。BeanFactory在查找,建立及管理bean时,会先查找其在内存中所保存的BeanDefinition,而后再根据BeanDefinition中的bean描述内容建立bean或返回所需的bean信息。

根据面向接口编程的原则,spring定义了接口BeanDefinitionRegistry注册管理全部的Bedifinition,实现此接口就能够管理bean的定义,DefaultListableBeanFactory类实现了此接口,所以DefaultListableBeanFactory类及其子类具备管理beanDefinition的功能。

Spring读取分析配置文件,根据配置文件中的定义,为这些bean建立对应的BeanDifinition,并将BeanDifinition注册至beanFactory中(具体表现为注册在DefaultListableBeanFactory类型的beanFactory)。当用户须要使用bean时,将传入bean的名称或类型给beanFactory,beanFactory从其所保存的beanDefinition中查找,当找到符合条件的beanDefinition后,则将根据beanDefinition中的bean信息建立bean对象,并返回给用户。

实例化Bean

Spring IoC容器如何实例化Bean呢?
传统应用程序能够经过new和反射方式进行实例化Bean。而Spring IoC容器则须要根据Bean定义里的配置元数据使用反射机制来建立Bean。在Spring IoC容器中根据Bean定义建立Bean主要有如下几种方式:
一、使用构造器实例化Bean,这是最简单的方式,Spring IoC容器即能使用默认空构造器也能使用有参数构造器两种方式建立Bean
二、使用静态工厂方式实例化Bean,使用这种方式除了指定必须的class属性,还要指定factory-method属性来指定实例化Bean的方法,并且使用静态工厂方法也容许指定方法参数,spring IoC容器将调用此属性指定的方法来获取Bean
三、使用实例工厂方法实例化Bean,使用这种方式不能指定class属性,此时必须使用factory-bean属性来指定工厂Bean,factory-method属性指定实例化Bean的方法,并且使用实例工厂方法容许指定方法参数,方式和使用构造器方式同样

示例:
一、构造器实例化Bean:

package cn.nevo.service.impl;

import cn.nevo.service.HelloApi;

public class HelloImpl implements HelloApi {
	private String message;
	
	public HelloImpl() {
		this.message = "Hello World!";
	}
	
	public HelloImpl(String message) {
		this.message = message;
	}

    @Override
    public void sayHello() {
        System.out.println(message);
    }
}

bean.xml
<!-- 使用默认构造参数实例化bean -->
  <bean id="hello" class="cn.nevo.service.impl.HelloImpl"></bean>
  
  <!-- 使用有参构造参数实例化bean -->
  <bean id="hello2" class="cn.nevo.service.impl.HelloImpl">
  	<constructor-arg index="0" value="New Hello World!"/>
  </bean>

测试
public class HelloServiceTest {

	@Test
	public void testClassPathXmlApplicationContextBaseOnClassPath() {
		// 1.准备配置文件,从当前类加载路径中获取配置文件
		// 2.初始化容器
		BeanFactory beanFactory = new ClassPathXmlApplicationContext("bean.xml");
		// 二、从容器中获取Bean
		HelloApi helloApi = beanFactory.getBean("hello", HelloApi.class);
		HelloApi helloApi2 = beanFactory.getBean("hello2", HelloApi.class);
		// 三、执行业务逻辑
		helloApi.sayHello();
		helloApi2.sayHello();
	}
}

二、静态工厂方式实例化Bean
返回HelloImpl实例的静态工厂类HelloImplStaticFactory.java
package cn.nevo.service.impl.staticfactory;

import cn.nevo.service.HelloApi;
import cn.nevo.service.impl.HelloImpl;

public class HelloImplStaticFactory {
	public static HelloApi getInstance(String message) {
		return new HelloImpl(message);
	}
}

bean.xml
<!-- 使用静态工厂方法实例化bean -->
  <bean id="statichello" class="cn.nevo.service.impl.staticfactory.HelloImplStaticFactory" factory-method="getInstance">
  	<constructor-arg index="0" value="static factory instance"/>
  </bean>

测试
HelloApi helloApi3 = beanFactory.getBean("statichello", HelloApi.class);
		helloApi3.sayHello();


三、实例工厂方式实例化Bean
用于产生HelloImpl实例的HelloImplInstanceFactory.java
package cn.nevo.service.impl.instancefactory;

import cn.nevo.service.HelloApi;
import cn.nevo.service.impl.HelloImpl;

public class HelloImplInstanceFactory {
	public HelloApi getInstance(String message) {
		return new HelloImpl(message);
	}
}

bean.xml
<!-- 使用实例工厂方法实例化bean -->
  <bean id="instancehello" class="cn.nevo.service.impl.instancefactory.HelloImplInstanceFactory"/>
  <bean id="instance" factory-bean="instancehello" factory-method="getInstance">
  	<constructor-arg index="0" value="instance factory"/>
  </bean>

测试

HelloApi helloApi4 = beanFactory.getBean("instance", HelloApi.class);
		helloApi4.sayHello();
相关文章
相关标签/搜索