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以松耦合的方式将它们组织在一起。各层之间不需要关心对象间的具体实现,以及如何创建,完全面向接口编程。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-26 11:27:35

Spring的IOC容器—依赖注入的相关文章

Spring中Ioc容器的注入方式

1 通过setter方法注入 bean类: package com.test; public class UserServiceImplement implements IUserService { private IUserDao user; public IUserDao getUser() { return user; } public void setUser(IUserDao user) { this.user = user; } public void saveUser() { us

Spring IOC源码详解之容器依赖注入

Spring IOC源码详解之容器依赖注入 上一篇博客中介绍了IOC容器的初始化,通过源码分析大致了解了IOC容器初始化的一些知识,先简单回顾下上篇的内容 载入bean定义文件的过程,这个过程是通过BeanDefinitionReader来完成的,其中通过 loadBeanDefinition()来对定义文件进行解析和根据Spring定义的bean规则进行处理 - 事实上和Spring定义的bean规则相关的处理是在BeanDefinitionParserDelegate中完成的,完成这个处理需

Spring IOC源代码具体解释之容器依赖注入

Spring IOC源代码具体解释之容器依赖注入 上一篇博客中介绍了IOC容器的初始化.通过源代码分析大致了解了IOC容器初始化的一些知识.先简单回想下上篇的内容 加载bean定义文件的过程.这个过程是通过BeanDefinitionReader来完毕的.当中通过 loadBeanDefinition()来对定义文件进行解析和依据Spring定义的bean规则进行处理 - 其实和Spring定义的bean规则相关的处理是在BeanDefinitionParserDelegate中完毕的,完毕这个

回客科技 面试的 实现ioc 容器用到的技术,简述BeanFactory的实现原理,大搜车面试的 spring 怎么实现的依赖注入(DI)

前言:这几天的面试,感觉自己对spring 的整个掌握还是很薄弱.所以需要继续加强. 这里说明一下spring的这几个面试题,但是实际的感觉还是不对的,这种问题我认为需要真正读了spring的源码后说出来的东西才有意义.这种面试的问法,也只能是面试的问法,对实际的掌握还是没有丝毫意义的.所以我认为 有机会一定要读下spring的源码 来过一遍 具体实现,这样的才是有意义的做法.同意的请举手. 这里说明一下这三个spring 面试问题: 1.回客科技 面试的 实现ioc 容器用到的技术 第1种 说

spring学习2:基于注解+xml实现ioc和依赖注入

spring学习2:基于注解+xml实现ioc和依赖注入 一.在spring配置文件中开启spring对注解的支持 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&qu

iOS控制反转(IoC)与依赖注入(DI)的实现

背景 最近接触了一段时间的SpringMVC,对其控制反转(IoC)和依赖注入(DI)印象深刻,此后便一直在思考如何使用OC语言较好的实现这两个功能.Java语言自带的注解特性为IoC和DI带来了极大的方便,要在OC上较好的实现这两个功能,需要一些小小的技巧. 控制反转和依赖注入 控制反转 简单来说,将一个类对象的创建由手动new方式改为从IOC容器内获取,就是一种控制反转,例如我们现在要创建一个ClassA类,则常规方法为 ClassA *a = [ClassA new]; 如果使用控制反转,

控制反转IOC与依赖注入DI

1. IoC理论的背景我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑. 图1:软件系统中耦合的对象 如果我们打开机械式手表的后盖,就会看到与上面类似的情形,各个齿轮分别带动时针.分针和秒针顺时针旋转,从而在表盘上产生正确的时间.图1中描述的就是这样的一个齿轮组,它拥有多个独立的齿轮,这些齿轮相互啮合在一起,协同工作,共同完成某项任务.我们可以看到,在这样的齿轮组中,如果有一个齿轮出了问题,就可能会影响到整个齿轮组

Spring核心技术IoC容器(八)

本文针对自动装载的一些注解进行描述. 基于注解的容器配置 @Required注解 @Required注解需要应用到Bean的属性的setter方法上面,如下面的例子: public class SimpleMovieLister { private MovieFinder movieFinder; @Required public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } //

好莱坞原则—Spring的IOC容器

IOC容器的概念,之前在学习SSH的时候,就有接触过.但那时候也仅仅是知道这么个概念,认为它非常难理解.事实上并非它难理解,而是我并没有停下来好好对它总结梳理过. IOC(Inversion of Control)简单介绍: 控制反转",并非一种技术.而是一种思想.一种主动提供服务的思想.所谓IOC,就是由Spring负责控制对象的生命周期和对象间的关系,与我们传统的在对象内部直接控制背道而驰. 在传统的程序开发中,完毕一个业务逻辑至少须要两个或两个以上的对象协助完毕.通常一个对象要使用另外一个