02-Spring3 IoC

 一、IoC

IoC—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。不创建对象,但是描述创建他们的方式。在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务,IoC容器负责将这些联系在一起。

         IoC设计模式重点关注组件的依赖性、配置以及生命周期。当然IoC也适用于简单类,而不只是组件。除了具有“Dependency Injection"(依赖注入)的昵称外,IoC还有另一个称呼,即Hollywood原则("Don't call me,I'll call you,请不要调用我,我将调用你),Ioc设计模式实现了“面向接口编程,而不是实现”的原则

IoC原理是基于OO设计原则的The Hollywood Principle:Don't call us, we'll call you(别找我,我会来找你的)。也就是说,所有的组件都是被动的(Passive),所有的组件初始化和调用都由容器负责。组件处在一个容器当中,由容器负责管理。简单的来讲,就是由容器控制程序之间的关系,而非传统实现中,由程序代码直接操控。这也就是所谓“控制反转”的概念。控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转。即不用new了而是通过Spring容器依赖注入完成或者说当某个java对象需要(依赖)另一个java对象时,不是自身直接创建依赖对象,而是由实现IoC的容器(如Spring框架的IoC容器)来创建,并将它注入需要这个依赖对象的java对象中。

依赖注入:是指在程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部的注入,Spring的依赖注入对调用者和被调用者几乎没有任何要求,完全支持对POJO之间的依赖关系的管理。

Spring采用动态及灵活的方式来管理各种对象,使对象与对象之间的具体实现相互透明

二、Hello IoC

下面我们来一个Hello World by Spring

1、  准备Jar包

核心jar包:spring-framework-3.0.5.RELEASE-with-docs.zip中dist目录查找如下jar包

org.springframework.asm-3.0.5.RELEASE.jar

org.springframework.core-3.0.5.RELEASE.jar

org.springframework.beans-3.0.5.RELEASE.jar

org.springframework.context-3.0.5.RELEASE.jar

org.springframework.expression-3.0.5.RELEASE.jar

 

依赖Jar包:spring-framework-3.0.5.RELEASE-dependencies.zip中查找如下依赖jar包

com.springsource.org.apache.log4j-1.2.15.jar

com.springsource.org.apache.commons.logging-1.1.1.jar

com.springsource.org.apache.commons.collections-3.2.1.jar

 

 

接口:

package com.iflytek.demo;
public interface HelloIoC {
	public void sayHello();
}

 

实现:

package com.iflytek.demo;
public class HelloIoCImpl implements HelloIoC {

	@Override
	public void sayHello() {
		System.out.println("Hello SpringIoC");
	}
}

 

现在接口和实现都已经实现了,下面来看Spring IoC容器如何来管理它,这就需要配置文件,让IoC容器知道要管理哪些对象helloioc.xml(resources目录下)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
	       http://www.springframework.org/schema/beans
	       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		   http://www.springframework.org/schema/context
		   http://www.springframework.org/schema/context/spring-context-3.0.xsd">
	<!-- id 表示你这个组件的名字,class表示组件类 -->
	<bean id="hello" class="com.iflytek.demo.HelloIoCImpl" />

</beans>

 

Ok,下面我们实例化一个IoC容器,然后从容器中获取需要的对象,然后调用接口完成我们需要的功能。

package com.iflytek.test;

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

import com.iflytek.demo.HelloIoC;
public class HelloIoCTest {

	@Test
	public void testSayHello() {
	    //1、读取配置文件实例化一个IoC容器
        ApplicationContext context = new ClassPathXmlApplicationContext("helloioc.xml");
        //2、从容器中获取Bean,注意此处完全“面向接口编程,而不是面向实现”
        HelloIoC helloIoC  = context.getBean("hello", HelloIoC.class);
        //3、执行业务逻辑
        helloIoC.sayHello();
	}
}

 

三、理解IoC容器

OK,我们来看看IoC容器,在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);

 

  (2) Resource resource = new ClassPathResource("classpath.xml");                

        BeanFactory beanFactory = new XmlBeanFactory(resource);

 

• ClassPathXmlApplicationContext:ApplicationContext实现,从classpath获取配置文件;

         BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath.xml");

 

• FileSystemXmlApplicationContext:ApplicationContext实现,从文件系统获取配置文件。

         BeanFactory beanFactory = new FileSystemXmlApplicationContext("fileSystemConfig.xml");

 

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

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

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

	@Test
	public void testFileSystemApplicationContext() {
		// 1.准备配置文件,从文件系统获取配置文件,默认是相对路径,可以指定绝对路径
		// 2.初始化容器
		BeanFactory beanFactory = new FileSystemXmlApplicationContext(
				"./resources/helloioc.xml");
		// 2、从容器中获取Bean
		HelloIoC helloIoC = beanFactory.getBean("hello", HelloIoC.class);
		// 3、执行业务逻辑
		helloIoC.sayHello();
	}

 

下面我们来看看IoC容器是如何工作的,以XML为例

1、  准备配置文件:在配置文件中声明Bean定义,即为Bean配置元数据

2、  由IoC容器进行解析元数据:IoC容器的Bean Reader读取并解析配置文件,根据定义生成BeanDefinition配置元数据对象,IoC容器根据BeanDifinition进行实例化,配置及组装Bean。

3、  实例化IoC容器:由客户端实例化容器,获取需要的Bean

02-Spring3 IoC

 

 

 

 

四、IoC配置

 

XML配置结构

<beans> 
	    <import resource=”resource1.xml”/>  
		<bean class="org.lxh.spring.StoneAxe" id="stoneAxe"></bean>
		<bean class="org.lxh.spring.SteelAxe" id="steelAxe"></bean>
		<bean class="org.lxh.spring.UserAxePerson" id="userAxePerson">
			<property name="axe"> <!-- 或<property name="axe" ref="steelAxe"> -->
		<!-- 指将哪个bean赋给name的(这里引用了其他的bean),对与local则是针对与当前的xml -->
				<ref local="steelAxe"/>
			</property><!-- 这里的name是跟setName中的name有关系而不跟字段有关 -->
		</bean>
	</beans>

 

标签说明:

1、beans:Spring配置文件的根元素

         2、bean:定义bean,

                   id:指定整个Bean中的唯一标识,不能和其他bean重复。

                   class:指定该Bean实例的实现类(全限定名)。

         3、property:向Spring容器注入的属性

             name:为该Bean指定一到多个别名。多个别名可以用“,”和“;”分割。

             ref:指定将哪个bean注入给bean,该值与对应bean的id值相同才可注入

         4、autowire:指定该Bean的属性的装配方式。

         5、scope:指定该Bean的存在。

         6、init-method:指定该Bean的初始化方法。

         7、destroy-method:指定该Bean的销毁方法。

         8、abstract:指定该Bean是否为抽象的。如果是抽象的,则spring不为它创建实例。

  9、parent:指定该Bean的父类标志或别名。

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

 

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() 方法。不过建议采用元数据定义。

 

 

Bean的命名

每个Bean可以有一个或多个id(或称之为标识符),在这里我们把第一个id称为“标识符”,其余id叫做“别名”。

1、不指定id,只配置必须的全限定类名,由IoC容器为其生成一个标识;

HelloIoC helloIoC = beanFactory.getBean(HelloIoC.class);

2、指定id,必须在Ioc容器中唯一;

HelloIoC helloIoC = beanFactory.getBean("id", HelloIoC.class);

3、指定name,这样name就是“标识符”,必须在Ioc容器中唯一;

HelloIoC helloIoC = beanFactory.getBean("name", HelloIoC.class);

4、指定id和name,id就是标识符,而name就是别名,必须在Ioc容器中唯一;

HelloIoC helloIoC = beanFactory.getBean("id", HelloIoC.class);
HelloIoC helloIoC = beanFactory.getBean("alias", HelloIoC.class);
String[] bean3Alias = beanFactory.getAliases("alias");

5、指定多个name,多个name用“,”、“;”、“ ”分割,第一个被用作标识符,其他的(alias1、alias2、alias3)是别名,所有标识符也必须在Ioc容器中唯一;

6、使用<alias>标签指定别名,别名也必须在IoC容器中唯一;

<bean name="bean" class="com.iflytek.demo.HelloIoCImpl"/>  
	 <alias alias="alias1" name="bean"/>  
	 <alias alias="alias2" name="bean"/>

 

实例化Bean

在传统应用程序中可以通过new和反射方式进行实例化Bean,而Spring IoC容器则需要根据Bean定义里的配置元数据使用反射机制来创建Bean。在Spring IoC容器中根据Bean定义创建。

1、  构造方法创建,Spring IoC容器即能使用默认空构造器也能使用有参数构造器

无参:

<bean id="hello" class="com.iflytek.demo.HelloIoCImpl" />

 

有参:

public class HelloIoCImpl02 implements HelloIoC02 {
	private String str;
	public HelloIoCImpl02(String str) {
		this.str = str;
	}
	@Override
	public void sayHello02() {
		System.out.println(str);
	}
}

 

<!-- id 表示你这个组件的名字,class表示组件类 -->
<bean id="hello" class="com.iflytek.demo.HelloIoCImpl" /><!-- 无参 -->

<bean id="hello02" class="com.iflytek.demo02.HelloIoCImpl02">
		<!-- 指定构造器参数 -->
	<constructor-arg index="0" value="Hello IoC by xdwang !" />
</bean>

 

2、  使用静态工厂方式实例化Bean,使用这种方式除了指定必须的class属性,还要指定factory-method属性来指定实例化Bean的方法,而且使用静态工厂方法也允许指定方法参数

public class HelloIoCStaticFactory {
	// 工厂方法
	public static HelloIoCImpl02 newInstance(String str) {
		// 返回需要的Bean实例
		return new HelloIoCImpl02(str);
	}
}

 

<!-- 使用静态工厂方法 -->  
	 <bean id="statichello" class="com.iflytek.demo02.HelloIoCStaticFactory" factory-method="newInstance">  
	      <constructor-arg index="0" value="Hello IoC by xdwang in static!"/>  
	 </bean>

 

3、使用实例工厂方法实例Bean,使用这种方式不能指定class属性,此时必须使用factory-bean属性来指定工厂Bean,factory-method属性指定实例化Bean的方法,而且使用实例工厂方法允许指定方法参数,方式和使用构造器方式一样

public class HelloIoCInstanceFactory {
	public HelloIoCImpl02 newInstance(String str) {
		return new HelloIoCImpl02(str);
	}
}

 

<!-- 1、定义实例工厂Bean -->  
<bean id="beanInstanceFactory" class="com.iflytek.demo02.HelloIoCInstanceFactory"/>  
<!-- 2、使用实例工厂Bean创建Bean -->  
<bean id="beanFactory"  factory-bean="beanInstanceFactory"  factory-method="newInstance">  
	<constructor-arg index="0" value="Hello IoC by xdwang in factory!"/>  
</bean>

 

 部分转自开涛博客。

 

 

 

相关推荐