Spring的IOC容器—依赖注入

前面一篇博客大致讲了一下Spring的IOC容器的原理,IOC即控制反转主要是依靠依赖注入的方式来实现的。依赖注入是指所依赖的对象不是由自己new出来的,而是用别的方式像打针似的注入进来。 其实说白了不管是控制反转还是依赖注入都说明了Spring采用动态、灵活的方式来管理各种对象。

Spring的依赖注入对调用者和被调用者几乎没有任何要求,完全支持对POJO之间依赖关系的管理。有以下几种注入方式: 


1. Setter 注入

因为对于javaBean来说,我们可以通过setter和getter方法分别改变对象和获取对象的属性。所以当前对象只要为其依赖对象所对应的属性添加setter方法,就可以通过setter方法将相应的依赖对象设置到被注入对象中。例如下面的代码:


 . Person接口
 
package com.tgb.depency;
/**
 * 定义Person接口 
 * @author MINGXUANYUN
 *
 */
public interface Person {
	
	//定义一个吃东西的方法
	public void eatSomething(); 
	
	//定义一个个人信息方法
	public String personInfo();
}

.Eat接口

package com.tgb.depency;
public interface Eat {
	//定义一个吃苹果的方法
	public String eatApple(); 
	
}

.Person的实现类

/**
 * Person的实现类
 * @author MINGXUANYUN
 */
public class Huohuo implements Person{
	
	private Eat eat;
	//默认的构造器
	public Huohuo(){}
	
	public Eat getEat() {
		return eat;
	}
	public void setEat(Eat eat) {
		this.eat = eat;
	}
	
	//实现Person吃东西的方法
	@Override
	public void eatSomething() {
		System.out.println(eat.eatApple());		
	}
	
	@Override
	public String personInfo() {
		return null;
	} 
}

.Eat的实现类

/**
 * 大口大口吃
 * @author MINGXUANYUN
 */
public class WideMouthEat implements Eat {

	@Override
	public String eatApple() {
		return"张大嘴巴吃苹果很粗鲁的!!!";
	}
}

.配置文件,将Person实例和Eat实例组织在一起

	<!--Setter注入测试实例 -->
		<bean id="Huohuo" class= "com.tgb.depencyimpl.Huohuo">
			<property name="eat" ref="WideMouthEat"></property>
		</bean>
		<bean id="WideMouthEat" class="com.tgb.depencyimpl.WideMouthEat">
		</bean>

从以上例子可以看出:Spring将bean与bean之间的依赖关系放到配置文件里管理,而不是写在代码里。通过配置文件,Spring精确的为每个bean注入每个属性。<bean>中的name属性是class属性的一个别名,class属性指真正的实现类(类的全名)。Spring自动接管每个bean里的 property元素定义。Spring再执行无参数的构造器,创建默认的bean后,调用对应的setter方法为程序注入属性值。


.主程序

public class SetterTest {

	public static void main(String[] args) {
		//实例化Spring的上下文
		ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");
		//强制转换接口类型
		Person person = (Person) ctx.getBean("Huohuo");
		//执行Person的eatSomething方法
		person.eatSomething();
	}

}

.运行结果输出 :

                     张大嘴巴吃苹果很粗鲁的!!!


说明: 主程序调用person.eatSomething方法,该方法方法体里需要有Eat的实例,但主程序里并没有任何地方为Person实例传入Eat实例,Eat实例是由Spring在运行期间动态注入的。Person实例不需要了解Eat实例的具体实现和创建过程。程序运行到Eat实例的时候,Spring自动创建Eat实例,然后注入给它的调用者,Person实例运行到需要Eat实例的时候,自动产生Eat实例。


这样有什么好处呢?如果我们需要另一个Eat实现类来为Person类使用。Person和其实现类都无需改变。只需要增加一个Eat的实现类,并在配置文件中配置就可以。


例如,增加Eat实现类ChewslowlyEat

import com.tgb.depency.Eat;

public class ChewslowlyEat implements Eat {
	@Override
	public String eatApple() {
		return "细嚼慢咽淑女的典范!!";
	}
}

修改配置文件:

<bean id="Huohuo" class= "com.tgb.depencyimpl.Huohuo">
   <property name="eat" ref="ChewslowlyEat"></property>
</bean>
<bean id="ChewslowlyEat" class="com.tgb.depencyimpl.ChewslowlyEat"></bean>	

输出结果:

    细嚼慢咽淑女的典范!!


2. 构造器注入

  指被注入对象通过在其构造函数中声明依赖对象的参数列表。


.定义一个Person实现类,用于构造器注入

/**
 * 构造器注入测试
 * @author MINGXUANYUN
 */
public class Yunyun implements Person{
    private String userName;
    private String kind;
    private Eat eat; 
    //默认构造方法
    public Yunyun(){};
    //构造注入所需的带参数构造器
    public Yunyun(Eat eat,String userName,String kind){
        this.eat = eat; 
        this.userName = userName;
        this.kind = kind; 
    }
    @Override
    public String personInfo() {
        return userName + "永远" + kind +"岁" + "----" + eat.eatApple();
    }
    @Override
    public void eatSomething() {
        // TODO Auto-generated method stub    
    }
}

在构造Yunyun实例时,创建三个成员变量userName、kind和对象类型的eat。但是并没有设置setter方法。在构造Person实例时,Spring为Person实例注入所依赖的Eat实例并且为两个成员变量赋值。构造注入的配置文件如下:

.xml配置文件

<!--构造器注入配置实例 -->
        <bean id="Yunyun" class= "com.tgb.depencyimpl.Yunyun">
        <constructor-arg index="0" ref="ChewslowlyEat"></constructor-arg>
        <constructor-arg index="1">  
            <value>朱火云 </value>  
          </constructor-arg>  
          <constructor-arg index="2">  
            <value>18</value>  
          </constructor-arg> 
        </bean>  
        <bean id="ChewslowlyEat" class="com.tgb.depencyimpl.ChewslowlyEat"/>

在配置文件中,不用<property>的形式,而是使用<constructor-arg>标签。ref属性指向其它<bean>标签的name属性。由于我们可能传入多个类型一致的构造参数。所以可以用type和index确定我们使用的哪一个构造函数。


.主程序

public class ConstructorTest {

	public static void main(String[] args) {	
		 String fileName = "bean.xml";  
         ApplicationContext ac = new FileSystemXmlApplicationContext(fileName);  
         // 取得一个实例 
         Yunyun yunyun =  (Yunyun) ac.getBean("Yunyun");  
         System.out.println(yunyun.personInfo());  
	}
}

输出结果:

              朱火云 永远18岁细嚼慢咽淑女的典范!!

3.静态工厂方法注入

    指通过调用静态工厂的方法来获取自己需要的对象。

.定义一个UserDao类

public class UserDao {
	public static UserDao getInstance(){
		return new UserDao("static factory method");
	}
	
	private String name=""; 
	public UserDao(String name){
		this.name = name; 
	}
	
	public void create(){
		System.out.println("create user from-" + name);
	}
}

.定义一个UserManager类

import com.tgb.depency.UserDao;

public class UserManager {
	//注入UserDao对象
	private UserDao userDao; 
	public void createUser(){
		userDao.create();
	}
	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}
	public UserDao getUserDao() {
		return userDao;
	}
}

.xml配置文件

<!-- 静态工厂方法注入 -->
		<bean name="userManager" class="com.tgb.depencyimpl.UserManager">
			<property name="userDao" ref="userDao"></property>
		</bean>
		<bean name="userDao" class="com.tgb.depency.UserDao" factory-method="getInstance">
		</bean>

factory-menthod定义了userDao 。Bean使用UserDao类的getInstance方法来创建自己的实例。

.主程序

public class StaticFactoryTest {

	public static void main(String[] args) {
		String fileName = "bean.xml";
		ApplicationContext ac = new FileSystemXmlApplicationContext(fileName);
		UserManager userManager = (UserManager) ac.getBean("userManager");
		userManager.createUser();
	}
}

输出结果:

                create user from-static factory method

总结:我们原来学三层的时候,UI层调用BLL、BLL调用DAO层。各层与各层之间虽然抽象出了接口层,调用接口。但是在new的时候指向的还是具体的实现。而现在Spring有效的管理各层之间对象的调用。 不管是Action调用Services对象,还是Services调用Dao对象,Spring以松耦合的方式将它们组织在一起。各层之间不需要关心对象间的具体实现,以及如何创建,完全面向接口编程。





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值