Spring设值注入

设值注入式值IOC容器使用属性的setter方法来注入被依赖的实例。这种注入方式简单直观,因而在Spring的依赖注入里大量使用。

看下面的代码,是Person接口的代码,该接口定义了一个Person规范。

package org.crazyit.app.service;
public interface Person
{
	//定义一个使用斧子的方法
	public void useAxe();
}

下面是Axe接口代码。

package org.crazyit.app.service;

public interface Axe
{
	//Axe接口里有个砍的方法
	public String chop();
}


Spring推荐面向接口编程,这样可以更好地让规范和实现分离,从而提供更好地解耦,对于一个Java EE应用,不管是DAO组件,还是业务逻辑组件,都应该先定义一个接口,该接口定义了该组件应该实现的功能,但功能的实现则由其实现类提供。



下面是Person类的实现类:

package org.crazyit.app.service.impl;

import org.crazyit.app.service.*;
public class Chinese  implements Person
{
	private Axe axe;
	//设值注入所需的setter方法
	public void setAxe(Axe axe)
	{
		this.axe = axe;
	}
	//实现Person接口的useAxe方法
	public void useAxe()
	{
		//调用axe的chop()方法,
		//表明Person对象依赖于axe对象
		System.out.println(axe.chop());
	}
}



上面的程序实现了Person接口的useAxe()方法,实现了该方法时调用了axe的chop()方法,这就是典型的依赖关系。


Spring的作用是什么呢?Spring容器的最大的作用就是以松耦合的方式来管理这种调用关系。在上面的Chinese类中,Chinese类并不知道它要调用的axe实例在哪里?也不知道axe实例如何实现的?它只是需要调用一个Axe实例,这个Axe实例将由Spring容器负责注入。


下面提供了一个Axe的实现类:StoneAxe

package org.crazyit.app.service.impl;

import org.crazyit.app.service.*;
 
public class StoneAxe  implements Axe
{
	public String chop()
	{
		return "石斧砍柴好慢";
	}
}


到现在为止,程序依然不知道Chinese类和哪个Axe实例耦合,Spring当然也不知道。实际上,Spring需要使用XML配置文件来指定实例之间的依赖关系。


下面我们看看配置文件:

<?xml version="1.0" encoding="GBK"?>
<!-- Spring配置文件的根元素,使用spring-beans-3.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://www.springframework.org/schema/beans"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
	<!-- 配置chinese实例,其实现类是Chinese -->
	<bean id="chinese" class="org.crazyit.app.service.impl.Chinese">
		<!-- 将stoneAxe注入给axe属性 -->
		<property name="axe" ref="steelAxe"/>
	</bean>
	<!-- 配置stoneAxe实例,其实现类是StoneAxe -->
	<bean id="stoneAxe" class="org.crazyit.app.service.impl.StoneAxe"/>
	 
</beans>

在配置文件中通常有两个属性:

id:指定该Bean的唯一标识,程序通过id属性来访问该Bean实例。

class:指定该Bean的实现类。此处不可再用接口,必须使用实现类,Spring容器会使用XML解析器读取该属性值啊,并利用反射来创建该实现类的实例。


Spring会自动接管每个<bean ../>定义里的<property/>元素定义,Spring会在调用无参数的构造器后、创建默认的Bean实例后,调用对应的Setter方法为程序注入属性值。<property../>定义的属性值将不再由该Bean来主动设置、管理,而是由Spring的注入。


每个Bean的id属性是该Bean的唯一标识,程序通过id属性访问Bean,Bean与Bean的依赖关系也通过id属性关联。


下面程序代码简单的获取了Person的实例,并调用该实例的useAxe方法。

package lee;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.crazyit.app.service.*;
import org.junit.Test;
 
public class BeanTest
{
	@Test
	public void testBean() throws Exception {
		//创建Spring容器
		ApplicationContext ctx = new   ClassPathXmlApplicationContext("bean.xml");
		//获取chinese 实例
		Person p = ctx.getBean("chinese" , Person.class);
		//调用useAxe()方法
		p.useAxe();
	}
}


上面的程序的主要两行代码实现了创建Spring容器,并通过Spring容器获取chinsee实例。从上面的程序可以看出,Spring是一个巨大的工厂,它可以生产处所有类型的Bean实例。程序获取Bean实例的方法是getBean(),正如上面:Person p = ctx.getBean("chinese" , Person.class);


然后我们看到的程序运行的结果是:石斧砍柴好慢


主程序调用Person熬使用的useAxe()方法时,该方法的方法体类需要使用Axe实例额,但程序没有任何方式将特定的Person实例和Axe实例耦合在一起。或者说,程序没有Person实例传入Axe实例,Axe实例由Spring在运行期间注入。


Person实例不仅不需要了解Axe实例的具体实现,甚至无需了解Axe的创建过程。Spring容器根据配置文件的指定,创建Person实例时,不仅创建了Person的默认实例,并为该实例依赖注入器所以来的Axe实例。



假设有一天,系统需要改变Axe的实现,这种改变,对于实际开发非常常见的情形,也许是因为技术的改进,也许是因为性能的优化,也许因为需求变化等。我们需要给出Axe的另一个实现,而Person接口、Chinese类的代码无需任何改变。


下面是Axe的另一个实现类:SteelAxe

package org.crazyit.app.service.impl;

import org.crazyit.app.service.*;
 
public class SteelAxe
	implements Axe
{
	public String chop()
	{
		return "钢斧砍柴真快";
	}
}

那么我们重新将配置文件稍微配置一下,如下:

加入一个bean:

<!-- 配置steelAxe实例,其实现类是SteelAxe -->
	<bean id="steelAxe" class="org.crazyit.app.service.impl.SteelAxe"/>

修改一下property的属性:

<property name="axe" ref="steelAxe"/>

运行结果如下:

钢斧砍柴真快



从上面这种切换可以看出,因为Chinese实例与具体的Axe实现类没有任何关系,chinese实例仅仅与Axe接口耦合,这就是保证了Chinese实例与Axe实例之间的松耦合——这也是Spring强调面向接口的原因。



Bean与Bean之间的依赖关系由Spring管理,Spring采用setter方法为目标Bean注入所依赖的Bean,这种方式被称为设置注入。


从上面程序可以看出,依赖注入以配置文件管理Bean实例之间的耦合,让Bean实例之间的耦合从代码层次分离出来。依赖注入式一种优秀的解耦方式。


从上面的介绍,不难发现使用Spring IoC容器的3个基本点:

1)应用程序的各组件面向接口编程。面向接口编程可以讲各个组件之间的耦合提升到接口层次,从而有利项目后期的扩展。

2)应用程度的各组件不再由程序主动产生,而是由Spring容器负责产生实例化。

3)Spring采用配置文件或Annotation来管理Bean的实现类,依赖关系,Spring容器根据配置文件、利用反射来创建实例,并为之注入依赖关系。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ItJavawfc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值