依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念。具体含义是:当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入。
不管是依赖注入,还是控制反转,都说明Spring采用动态、灵活的方式来管理各种对象。对象与对象之间的具体实现互相透明。在理解依赖注入之前,看如下这个问题在各种社会形态里如何解决:一个人(Java实例,调用者)需要一把斧子(Java实例,被调用者)。像前面博客中提到struts框架,Hibernate框架似的,spring同样也是一个开源的框架。使用框架的的优势在于分层结构,每层有相应的框架,减少开发工作量,减少组件之间的耦合。struts框架应用web层,Hibernate框架应用持久层,spring应用两者之间。
我觉得,框架是出于聪明的赖人之手。聪明是说他们开发封装每层框架,把复杂的操作全部封装在框架中。而赖人是说他所有复杂的操作实现全部交给计算机来实现,减少人们的开发工作量,把工作的注意力集中在业务逻辑上。
那我们来介绍一下struts框架。
spring框架是一个开源的轻量级的基于IOC与AOP核心技术的容器框架,主要是解决企业的复杂操作实现。
那IOC与AOP,到底如何解释呢,在看spring视频中,两个专业术语一定必须要懂得。
IOC:inverse of Control:控制反转。意思是程序中的之间的关系,不用代码控制,而完全是由容器来控制。在运行阶段,容器会根据配置信息直接把他们的关系注入到组件中。同样,这也是依赖注入的含义。依赖注入和控制反转其实是一个概念。只不过强调的不同而已,依赖注入强调关系的注入是由容器在运行时完成,而控制反转强调关系是由容器控制。其实本质是一样的。
用代码演示一下控制反转是如何实现的。
1。新建一个普通的Java项目。
2。引入相应的jar包。Spring.jar,log4j-1.2.14.jar(提供日志功能的),commons-logging.jar
3。提供log4j.properties配置文件。(日志jar包可以不用添加)
4。提供配置文件ApplicationContext.xml文件
5。开始写代码。
- package ioc.iocsample;
- /**
- * 学校类
- * @author lhy
- *
- */
- public class School {
- private String name;
- public School(String name)
- {
- this.name=name;
- }
- public void printInfo()
- {
- System.out.println("该学校的名称是:"+name);
- }
- }
- package ioc.iocsample;
- /**
- * 学生类
- * @author lhy
- *
- */
- public class Student {
- public int id;
- public String name;
- private School school;
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public School getSchool() {
- return school;
- }
- public void setSchool(School school) {
- this.school = school;
- }
- }
配置文件:
- <?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:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
- <bean id="school" class="ioc.iocsample.School">
- <constructor-arg index="0">
- <value>廊坊师院</value>
- </constructor-arg>
- </bean>
- <bean id="student" class="ioc.iocsample.Student">
- <property name="id" value="001"/>
- <property name="name" value="张三"/>
- <property name="school" ref ="school"/>
- </bean>
- </beans>
客户端进行测试,其中学生类Student中有School中的引用,测试该学生就读的学校的名称如下:
- package ioc.iocsample;
- import org.springframework.beans.factory.BeanFactory;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- public class Client {
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
- Student student=(Student)factory.getBean("student");
- student.getSchool().printInfo();
- }
- }
其中,在程序中不用实例化学生类,学校类,直接由容器中的beanFactory直接创建,隐藏了创建了细节。同时,程序中也不用关心学生类与学校类之间的依赖关系,而由容器来进行负责,在运行的时候,容器会把属性值及依赖关系注入学生类和学校类中的javabean中(其实在此School和Student就是一个javaBean。javaBean就是一个按照一定的原则封装的java类而已。)
其中依赖注入包括两种:一种赋值注入(使用getter和setter方法);另一种使用构造器注入。
看程序中student中的ID,name都是使用get,set来赋值的:那在配置文件是如下配置:
<property name="id" value="001"/>
<property name="name" value="张三"/>
并且Student中的school属性是School类型,则在容器中是如下配置的:
<property name="school" ref ="school"/>
而在程序中的School中的name是构造器赋值的,则容器中是如下配置的:
<constructor-arg index="0">
<value>廊坊师院</value>
</constructor-arg>
构造器中一个参数,则索引值是从0开始,若是有多个,依次递增。
若构造器中的是一个类,则使用bean标签
<constructor-arg index="0">
<bean class="具体的类">
</constructor-arg>
PS:当再次看博客,有了新的感触。2012年8月7日 15:06:52
spring中的依赖注入DI(dependence injection)共有三种方式:第一种是接口注入(Interface Injection)第二种是get set注入(set/get Injection)第三种是构造器注入(Constructor Injection)
三种注入方式的区别:
1.接口注入:组件需要依赖特定接口的实现,其中的加载接口实现和接口实现的具体对象都是由容器来完成。这样,接口必须依赖容器,这样的组件具有侵入性,降低了重用性。其中如J2EE开发中常用的Context.lookup(ServletContext.getXXX),都是接口注入的表现形式。(这种注入方式不是常用的)
2.getter/setter方式注入:对于需要注入的东西比较明确。符合java的设计规则。更适合java开发人员,使用起来更加自然,更加方便。
3.构造器方式注入:在类加载的时候,就已经注入依赖的组件。但是若是参数多的话,使用起来不方便。
但是后两种注入方式是spring常用的,而第一种接口注入方式不常用。
网友评论:
控制反转,和依赖注入是同一个意思,我觉得应该重点去了解什么是依赖,而后控制反转、依赖注入就有体会了;关于依赖,可以查看UML相关的书籍,重点去看java对象之间的关系是怎样的,而所谓的依赖就是对象之间的一种关系,比如a对象依赖于b对象,那么a类中就会有b类的引用(简单理解就是拥有b类的这么一个属性),也就是说a对象要想执行一个完整的功能,必须建立一个前提——a对象中的b类属性已经实例话,并且拥有b类的一切功能;现在可以去了解什么是依赖注入了,就像前面说过的,a对象想完成一个完整的功能,要先为自己的b类属性实例化,而在MVC模式中,这种现象很常见,为了简化这种实例化的工作,spring容器就产生了,它可以统一管理这种实例化频繁的操作,就是说这种本来应由自己实例化的工作交给Spring容器去控制了,也就是说控制反转了,实现的方案之一是在上述a类中提供一个关于b类的setter方法,这个方法会被Spring容器控制。
2、控制反转:就是系统知道A需要B,会提前将B给A,不需要A再要了。
其具体,你使过spring就知道了,一使便知。
就是要什么给什么,按照需要来。能够控制对象的产生,解耦合
控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心。 控制反转一般分为两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)。依赖注入应用比较广泛。 依赖注入:组件不做定位查询,只提供普通的Java方法让容器去决定依赖关系。容器全权负责的组件的装配,它会把符合依赖关系的对象通过JavaBean属性或者构造函数传递给需要的对象。通过JavaBean属性注射依赖关系的做法称为设值方法注入(Setter Injection);将依赖关系作为构造函数参数传入的做法称为构造子注入(Constructor Injection) 区别: 控制反转:创建对象实例的控制权从代码控制剥离到IOC容器控制,实际就是你在xml文件控制,侧重于原理。 依赖注入:创建对象实例时,为这个对象注入属性值或其它对象实例,侧重于实现。