Spring4 IOC详解


上一章对Spring做一个快速入门的教程,其中只是简单的提到了IOC的特性。本章便对Spring的IOC进行一个详解。主要从三个方面开始:基于xml文件的Bean配置,基于注解的Bean配置和IOC容器Bean的生命周期。


基于xml文件的Bean配置

首先是applicationContext.xml文件,这可是核心文件。

配置一个bean,需要一个id去唯一标识它,用class指定Bean对象的路径,作用域默认是单例。

通过prototype进行属性赋值,name是属性名,value是值,也可以用ref引用对象,用list,map设置集合。

用SpEL表达式语言赋值,用p命名空间简化赋值,用继承和依赖简化代码。

<?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:util="http://www.springframework.org/schema/util"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
	
	<!-- 配置一个 bean 
		bean中有一个id,且id是唯一的。若不指名则为该类的类名并首字母小写。
		property 中有一个name,其name就是生产了setter方法的属性,value便是其值。
	-->
	<!-- Bean 的作用域
		singleton:单例,默认值,容器初始化创建bean实例,在整个生命周期内只创建一个bean。
		prototype:原型,容器初始化不创建bean实例,每次请求的时候会创建一个新的bean
	 -->
	<bean id="entity" class="com.itdragon.spring.my.Entity" scope="prototype">
		<!-- 属性赋值 
			属性注入使用 <property> 元素, 使用 name 属性指定 Bean 的属性名称,value 属性或 <value> 子节点指定属性值 
		-->
		<property name="intValue" value="1"></property>
		<!-- 引用bean
			细节:
			1. 用ref 是引用外部bean
			2. 也可以直接写在当前bean里面,这就是内部bean, 内部bean是不能被外部引用
		-->
		<property name="spELEntity"  ref="spELEntity"></property>
		<!-- 构造器注入
			构造器注入在 <constructor-arg> 元素里声明属性, <constructor-arg> 中没有 name 属性,按照构造器参数顺序赋值
			细节:
			1. 也可以用index(按索引匹配入参),和type(按类型匹配入参)去指定赋值。实际上是没有必要的
			2. 使用构造器注入的前提是 entity 被初始化。
			3. 特殊字符,需要用 <![CDATA[内容]]> 这属于xml语法
		 -->
		 <constructor-arg value="1.1" />
		 <constructor-arg >
		 	<value><![CDATA[<ITDragon>]]></value>
		 </constructor-arg>
		 <property name="listValue">
		 	<list>
		 		<value>欢迎阅读</value>
		 		<value>ITDragon</value>
		 		<value>的博客!</value>
		 	</list>
		 </property>
		 <property name="mapValue">
		 	<map>
		 		<entry key="one" value="1"></entry>
		 		<entry key="two" value="2"></entry>
		 	</map>
		 </property>
	</bean>
	
	<!-- SpEL 表达式语言, #{…} 作为定界符, 操作和java相似-->
	<bean id="spELEntity" class="com.itdragon.spring.my.SpELEntity">
		<property name="intSpel" value="#{1}"></property>
		<property name="floatSpel" value="#{entity.intValue + 0.2}"></property>
		<property name="stringSpel" value="#{'Spring4基础教程'}"></property>
		<property name="bSpel" value="#{2 >= 1}"></property>
	</bean>
	
	<!-- 使用 p 命名空间  
		给Entity 对象 的intValue 字段设置 为2 ,根据名称匹配SpEL对象
		自动装配 autowire (不常用)
		byName(根据名称自动装配): 必须将目标 Bean 的名称和属性名设置的完全相同.反之不能
		byType(根据类型自动装配): 若 IOC 容器中有多个与目标 Bean 类型一致的 Bean. 在这种情况下, 不能执行自动装配.
	-->
	<bean id="entity2" class="com.itdragon.spring.my.Entity" 
		p:intValue="2"  autowire="byName" />
		
	<!-- 继承 依赖 
		如果 被继承的bean 不想被继承,则要加上 abstract="true"
		依赖:如果被依赖的bean,没有实例化,则会报错。如果有多个依赖需用","分开
	-->
	<bean id="entity3" class="com.itdragon.spring.my.Entity" 
		parent="entity" depends-on="spELEntity" />
		
	<!-- 使用外部属性文件 在Spring操作数据库的时候再讲 -->
</beans> 
实体类Entity和SpELEntity

import java.util.List;
import java.util.Map;
public class Entity {
	
	private int intValue;
	private float floatValue;
	private String stringValue;
	private SpELEntity spELEntity;
	private Map<String, Object> mapValue;
	private List<Object> listValue;
	
	public Entity() {
	}
	public Entity(float floatValue, String stringValue) {
		this.floatValue = floatValue;
		this.stringValue = stringValue;
	}
	public int getIntValue() {
		return intValue;
	}
	public void setIntValue(int intValue) {
		this.intValue = intValue;
	}
	public float getFloatValue() {
		return floatValue;
	}
	public void setFloatValue(float floatValue) {
		this.floatValue = floatValue;
	}
	public String getStringValue() {
		return stringValue;
	}
	public void setStringValue(String stringValue) {
		this.stringValue = stringValue;
	}
	public SpELEntity getSpELEntity() {
		return spELEntity;
	}
	public void setSpELEntity(SpELEntity spELEntity) {
		this.spELEntity = spELEntity;
	}
	public Map<String, Object> getMapValue() {
		return mapValue;
	}
	public void setMapValue(Map<String, Object> mapValue) {
		this.mapValue = mapValue;
	}
	public List<Object> getListValue() {
		return listValue;
	}
	public void setListValue(List<Object> listValue) {
		this.listValue = listValue;
	}
	@Override
	public String toString() {
		return "Entity [intValue=" + intValue + ", floatValue=" + floatValue
				+ ", stringValue=" + stringValue + ", spELEntity=" + spELEntity
				+ ", mapValue=" + mapValue + ", listValue=" + listValue + "]";
	}
}
public class SpELEntity {
	
	private int intSpel;
	private float floatSpel;
	private boolean bSpel;
	private String stringSpel;
	public int getIntSpel() {
		return intSpel;
	}
	public void setIntSpel(int intSpel) {
		this.intSpel = intSpel;
	}
	public float getFloatSpel() {
		return floatSpel;
	}
	public void setFloatSpel(float floatSpel) {
		this.floatSpel = floatSpel;
	}
	public boolean isbSpel() {
		return bSpel;
	}
	public void setbSpel(boolean bSpel) {
		this.bSpel = bSpel;
	}
	public String getStringSpel() {
		return stringSpel;
	}
	public void setStringSpel(String stringSpel) {
		this.stringSpel = stringSpel;
	}
	@Override
	public String toString() {
		return "SpELEntity [intSpel=" + intSpel + ", floatSpel=" + floatSpel
				+ ", bSpel=" + bSpel + ", stringSpel=" + stringSpel + "]";
	}

}
测试Main方法。 首先要创建一个容器,然后通过bean的id获取到实例,这样就可以开始相关的操作。其中entity, entity2,entity3对应三块不同的知识点。

import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {

	public static void main(String[] args) {
		/**
		 * ClassPathXmlApplicationContext:从 类路径下加载配置文件,建议用该方法
		 * FileSystemXmlApplicationContext: 从文件系统中加载配置文件
		 */
		// 1. 创建 Spring 的 IOC 容器
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		/**
		 * entity 属性注入,构造器注入,对象引用,集合,SpEL,(重点)
		 * entity2 自动装配和P命名空间
		 * entity3 继承和依赖,作用域
		 */
		// 2. 从 IOC 容器中获取 bean 的实例
		Entity entity = (Entity) ctx.getBean("entity");
		
		// 3. 使用 bean
		System.out.println(entity.toString());
//		System.out.println(ctx.getBean("entity") == ctx.getBean("entity")); 使用 prototype 打印的是false
		
		ctx.close();
	}
	
}

Entity [intValue=1, floatValue=1.1, stringValue=<ITDragon>, spELEntity=SpELEntity [intSpel=1, floatSpel=1.2, bSpel=true, stringSpel=Spring4基础教程], mapValue={one=1, two=2}, listValue=[欢迎阅读, ITDragon, 的博客!]]


基于注解的Bean配置

相对于xml的配置,注解的方式显得异常简单。主要分两个步骤

第一步:在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"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/util 
		http://www.springframework.org/schema/util/spring-util-4.0.xsd
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context-4.0.xsd">
	
	<!-- 配置自动扫描指定目录下的包 
		resource-pattern="xxx/*.class" 属性过滤特定的类 
	-->
	<context:component-scan base-package="com.itdragon.spring.my" >
		<!-- annotation 是针对指定的类 和 assignable 是针对所有继承或者扩展该类的类-->
		<!-- context:exclude-filter 只排除expression里面的内容 
		<context:exclude-filter type="annotation" expression=""/>
		 -->
		<!-- context:include-filter 只包含expression里面的内容 
			需配合 use-default-filters="false"(默认是true) 一起使用
		<context:include-filter type="annotation" expression=""/>
		-->
	</context:component-scan>
	
</beans> 
第二步:在对象上用注解。这四几个注解的作用一样,只是为了结构清晰,取的名字不同罢了。

使用方法很简单:直接在类上加注解即可。无参数的情况,bean的id默认是小写字母开头的类名。也可以指定参数@Commponent("指定参数"),那bean的id就是指定参数。

@Component: 基本注解, 标识了一个受 Spring 管理的组件
@Respository: 标识持久层组件
@Service: 标识服务层(业务层)组件
@Controller: 标识表现层组件

public interface AnnoRepository {
	
	public void hello();

}
import org.springframework.stereotype.Repository;
@Repository
public class AnnoRepositoryImp implements AnnoRepository{

	@Override
	public void hello() {
		System.out.println("AnnoRepository : hello!");
	}

}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class AnnoService {
	
	@Autowired
	private AnnoRepository annoRepository;
	
	public void hello() {
		System.out.println("AnnoService : hello!");
		annoRepository.hello();
	}

}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class AnnoController {

	@Autowired
	private AnnoService annoService;
	
	public void execut() {
		System.out.println("AnnoController : hello !");
		annoService.hello();
	}
	
}
这里还有一个注解Autowired, <context:component-scan> 元素会自动组件装配被Autowired修饰的对象。
测试类:虽然applicationContext.xml中没有annoController的bean配置,但我们有注解!

import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {

	public static void main(String[] args) {
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		AnnoController annoController = (AnnoController) ctx.getBean("annoController");
		annoController.execut();
		ctx.close();
	}
	
}
AnnoController : hello !
AnnoService : hello!
AnnoRepository : hello!
有没有觉得基于注解的bean配置比基于xml的bean配置简单很多。

IOC容器Bean的生命周期

step1 实例化,通过构造器创建 Bean 实例
step2 赋值,为 Bean 的属性设置值
step3 init-method,调用 Bean 的初始化方法(init-method)
step4 destroy-method,当容器关闭时, 调用 Bean 的销毁方法(destroy-method)

以上代码都是笔者亲测可用的,不要嫌麻烦,麻烦是学不好的,如果有什么问题和建议可以留言,我会及时处理。http://blog.csdn.net/qq_19558705/article/details/49994191

更多干货等你来拿 http://www.itit123.cn/



Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐