文档章节

关于Spring的IOC原理

huser_YJ
 huser_YJ
发布于 2014/09/22 16:38
字数 2429
阅读 51
收藏 1
 Spring   IOC原理


内部最核心的就是IOC了,直观地讲,就是容器控制程序之间的关系,而非传统实现中,由程序代码直接操控。这也就是所谓“控制反转”的概念所在。控制权由应用代码中转到了外部容器,控制权的转移是所谓反转。

IoC还有另外一个名字——“依赖注入(Dependency Injection)”。从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,形象地说,即由容器动态地将某种依赖关系注入到组件之中。


依赖注入的三种实现类型:接口注入、 Setter 注入和构造器注入。

1、接口注入

public class ClassA 
{ 
private InterfaceB clzB; 
public void doSomething() { 
Ojbect obj =Class.forName(Config.BImplementation).newInstance(); 
clzB = (InterfaceB)obj; 
clzB.doIt() 
} 
…… 
}
上面的代码中, ClassA 依赖于 InterfaceB  的实现,如何获得 InterfaceB 实现类的实例?传统的方法是在代码中创建 InterfaceB 实现类的实例,并将起赋予 clzB 。  而这样一来,  ClassA 在编译期即依赖于 InterfaceB  的实现。为了将调用者与实现者在编译期分离,于是有了上面的代码.  我们根据预先在配置文件中设定的实现类的类名  (Config.BImplementation) ,动态加载实现类,并通过 InterfaceB 强制转型后为 ClassA  所用。这就是接口注入的一个最原始的雏形。  而对于一个 接口 型 IOC  容器而言,加载接口实现并创建其实例的工作由容器完成,见如下代码。 

public class ClassA 
{ 
private InterfaceB clzB; 
public Object doSomething(InterfaceB b) 
{ 
clzB = b; 
return clzB.doIt(); 
} 
…… 
}
在运行期, InterfaceB 实例将由容器提供。 接口型 IOC 发展较早(有意或无意),在实际中得到了普遍应用,即使在 IOC 
的概念尚未确立时,这样的方法也已经频繁出现在我们的代码中。
public class 
MyServlet extends HttpServlet { 
public void doGet(HttpServletRequest 
request,HttpServletResponse response)throws ServletException, IOException { …… } 
}
上面的代码应该有印象吧
这也是一个 接口 型注入, HttpServletRequest 和 HttpServletResponse 实例由 Servlet  Container 在运行期动态注入。 


2、Setter( 设值 ) 注入 

各种类型的依赖注入模式中,设值注入模式在实际开发中得到了最广泛的应用。

public class 
ClassA { 
private InterfaceB clzB; 
public void setClzB(InterfaceB clzB) 
{ 
this. clzB = clzB; } 
…… 
}


再如下面的例子:

这里是TextEditor.java文件的内容:

package com.yiibai;

public class TextEditor {
   private SpellChecker spellChecker;

   // a setter method to inject the dependency.
   public void setSpellChecker(SpellChecker spellChecker) {
      System.out.println("Inside setSpellChecker." );
      this.spellChecker = spellChecker;
   }
   // a getter method to return spellChecker
   public SpellChecker getSpellChecker() {
      return spellChecker;
   }

   public void spellCheck() {
      spellChecker.checkSpelling();
   }
}
在这里,需要检查setter方法​​的命名约定。设置我们使用setSpellChecker()方法,这是非常类似于Java POJO类的变量的拼写检查器。让我们创造另一个相关的类文件SpellChecker.java,内容如下:
package com.yiibai;

public class SpellChecker {
   public SpellChecker(){
      System.out.println("Inside SpellChecker constructor." );
   }

   public void checkSpelling() {
      System.out.println("Inside checkSpelling." );
   }
   
}
以下是MainApp.java文件的内容:

package com.yiibai;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = 
             new ClassPathXmlApplicationContext("Beans.xml");

      TextEditor te = (TextEditor) context.getBean("textEditor");

      te.spellCheck();
   }
}
配置文件为

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="com.yiibai.TextEditor">
      <property name="spellChecker" ref="spellChecker"/>
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="com.yiibai.SpellChecker">
   </bean>

</beans>

3、构造器注入 

依赖关系是通过类构造函数建立的 容器通过调用类的构造方法将其所需的依赖关系注入其中 

public 
class DIByConstructor { private final DataSource dataSource; 
public 
DIByConstructor(DataSource ds) { 
this.dataSource = ds; 
} 
…… 
}
再如下例子:

在需要注入的类中,编写注入的构造方法

public PersonServiceBean(PersonDao personDao, String string) {
		this.personDao = personDao;
		this.string = string;
	}
在beans.xml中申明被注入的类

<bean id="personDao" class="com.dwt1220.PersonDaoBean" />
在注入类的<bean>标签体中使用<constructor-arg>标签

<bean id="personService" class="com.dwt1220.PersonServiceBean">
		<!--index=构造方法的参数位置(下标从0开始), type=注入的类型,ref=注入类在beans.xml中注册的ID -->
		<constructor-arg index="0" type="com.dwt1220.PersonDao" ref="personDao"/>
		<constructor-arg index="1" value="dwt1220" />
	</bean>
PersonServiceBean.java类

package com.dwt1220;

public class PersonServiceBean implements PersonService {
	private PersonDao personDao;
	private String string;
	
	public PersonServiceBean(PersonDao personDao, String string) {
		this.personDao = personDao;
		this.string = string;
	}

	public PersonDao getPersonDao() {
		return personDao;
	}

	public void setPersonDao(PersonDao personDao) {
		this.personDao = personDao;
	}

	public void save() {
		System.out.println("这是save方法");
		System.out.println(string);
	}
}
beans.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
	<bean id="personDao" class="com.dwt1220.PersonDaoBean" />
	<bean id="personService" class="com.dwt1220.PersonServiceBean">
		<!--index=构造方法的参数位置(下标从0开始), type=注入的类型,ref=注入类在beans.xml中注册的ID -->
		<constructor-arg index="0" type="com.dwt1220.PersonDao" ref="personDao"/>
		<constructor-arg index="1" value="dwt1220" />
	</bean>
</beans>
Test.java

package com.dwt1220;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
	public static void main(String[] args) {
		AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
		PersonService personService = (PersonService) ctx.getBean("personService");
		personService.save();
		ctx.close();
	}
}

动态注入,让一个对象的创建不用new了,可以自动的生产,这其实就是利用java里的反射  
反射其实就是在运行时动态的去创建、调用对象,Spring就是在运行时,跟xml Spring的配置  

文件来动态的创建对象,和调用对象里的方法的 。  


Spring它是一个开源的项目,而且目前非常活跃;它基于IoC(Inversion of Control,反向控制)和AOP的构架多层j2ee系统的框架,但它不强迫你必须在每一层 中必须使用Spring,因为它模块化的很好,允许你根据自己的需要选择使用它的某一个模块;它实现了很优雅的MVC,对不同的数据访问技术提供了统一的 接口,采用IoC使得可以很容易的实现bean的装配,提供了简洁的AOP并据此实现Transcation Managment,等等


优点  
a. Spring能有效地组织你的中间层对象,不管你是否选择使用了EJB。如果你仅仅使用了Struts或其他为J2EE的 API特制的framework,Spring致力于解决剩下的问题。  
b. Spring能消除在许多工程中常见的对Singleton的过多使用。根据我的经验,这是一个很大的问题,它降低了系统的可测试性和面向对象的程度。  
c. 通过一种在不同应用程序和项目间一致的方法来处理配置文件,Spring能消除各种各样自定义格式的属性文件的需要。曾经对某个类要寻找的是哪个魔法般的属性项或系统属性感到不解,为此不得不去读Javadoc甚至源编码?有了Spring,你仅仅需要看看类的JavaBean属性。Inversion of Control的使用(在下面讨论)帮助完成了这种简化。  
d. 通过把对接口编程而不是对类编程的代价几乎减少到没有,Spring能够促进养成好的编程习惯。  
e. Spring被设计为让使用它创建的应用尽可能少的依赖于他的APIs。在Spring应用中的大多数业务对象没有依赖于Spring。  
f. 使用Spring构建的应用程序易于单元测试。  
g. Spring能使EJB的使用成为一个实现选择,而不是应用架构的必然选择。你能选择用POJOs或local EJBs来实现业务接口,却不会影响调用代码。  
h. Spring帮助你解决许多问题而无需使用EJB。Spring能提供一种EJB的替换物,它们适用于许多web应用。例如,Spring能使用AOP提供声明性事务管理而不通过EJB容器,如果你仅仅需要与单个数据库打交道,甚至不需要一个JTA实现。  
i. Spring为数据存取提供了一个一致的框架,不论是使用的是JDBC还是O/R mapping产品(如Hibernate)。  
Spring确实使你能通过最简单可行的解决办法来解决你的问题。而这是有有很大价值的。


使用IOC框架应该注意什么
使用IOC框架产品能够给我们的开发过程带来很大的好处,但是也要充分认识引入IOC框架的缺点,做到心中有数,杜绝滥用框架。
第一、软件系统中由于引入了第三方IOC容器,生成对象的步骤变得有些复杂,本来是两者之间的事情,又凭空多出一道手续,所以,我们在刚开始使用IOC框架的时候,会感觉系统变得不太直观。所以,引入了一个全新的框架,就会增加团队成员学习和认识的培训成本,并且在以后的运行维护中,还得让新加入者具备同样的知识体系。
第二、由于IOC容器生成对象是通过反射方式,在运行效率上有一定的损耗。如果你要追求运行效率的话,就必须对此进行权衡。
第三、具体到IOC框架产品(比如:Spring)来讲,需要进行大量的配制工作,比较繁琐,对于一些小的项目而言,客观上也可能加大一些工作成本。
第四、IOC框架产品本身的成熟度需要进行评估,如果引入一个不成熟的IOC框架产品,那么会影响到整个项目,所以这也是一个隐性的风险。
我们大体可以得出这样的结论:一些工作量不大的项目或者产品,不太适合使用IOC框架产品。另外,如果团队成员的知识能力欠缺,对于IOC框架产品缺乏深入的理解,也不要贸然引入。最后,特别强调运行效率的项目或者产品,也不太适合引入IOC框架产品,象WEB2.0网站就是这种情况。

© 著作权归作者所有

huser_YJ
粉丝 2
博文 21
码字总数 28816
作品 0
武汉
私信 提问
那些年,我们一起追的Spring

学无止境,但仍需及时总结。 自去年开始写作以来,写了一些关于Spring的文章,今天将它们汇总起来,一方面方便大家阅读,另一方面,也是一次小的复盘总结。 IOC 首先是Spring的IOC,也就是控...

SexyCode
2018/08/14
0
0
三条路线告诉你如何掌握Spring IoC容器的核心原理

一、前言 前三篇已经从历史的角度和大家一起探讨了为什么会有Spring,Spring的两个核心概念:IoC和AOP的雏形,Spring的历史变迁和如今的生态帝国。本节的主要目的就是通过一个切入点带大家一...

Java小铺
2018/08/27
0
0
面试阿里等互联网公司java岗位时,关于Spring到底需要掌握什么?

之前分享过一些BAT面试必会的文章,一些读者看了,问过我,Spring 这篇需要掌握一些什么?相信这个问题也是很多读者心中的疑问,今天就来聊一下关于 Spring,我从面试中收获的一些经验。 一....

别打我会飞
04/17
0
0
Spring IoC & DI

IOC诞生的历史 在没有IoC时,关联不同模块是通过类实例实现的,代码可能是这样子的: 当YourServiceImpl的接口不变时,只需要根据业务需要更换不同的YourService实现类即可。一旦更换实现类时...

classfly
2018/06/18
0
0
阿里的Spring框架面试题到底有多难?这五大问题你又掌握了多少!

前言 还在机械地打代码?我们很多开发者在开发 Spring 的程序的时候,很多的情况下,都是被动的接受了前辈们为我们做好的 Spring 特性案例。这样以来,确实在很大的程度上减少了我们开发的成...

java知识分子
02/21
0
0

没有更多内容

加载失败,请刷新页面

加载更多

mysql mysql中的视图

视图是由数据库中的一个表或者多个表导出的虚拟表,方便用户操作。其内容是由查询定义。 视图是存储在数据库中的查询的sql语句。 一、创建视图 1. 查看创建视图的权限 select Select_priv,C...

edison_kwok
13分钟前
0
0
以太坊中文文档翻译-账号

本文原文链接 点击这里获取Etherscan API 中文文档(完整版) 完整内容排版更好,推荐读者前往阅读。 账号(Account) 账号及地址相关的 API,接口的参数说明请参考Etherscan API 约定, 文档中...

Tiny熊
23分钟前
0
0
Springboot 集成redis

这里只做单机版简单集成,不过为项目中使用 1.在pom文件中引入支持 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redi......

贾峰uk
54分钟前
3
0
Qt编写安防视频监控系统4-删除视频

一、前言 一般会有两种处理方式来删除视频,一种是鼠标右键菜单,删除当前视频或者删除所有视频,一种是直接按住当前视频,移到视频通道界面以外就表示删除当前视频,这也是个比较人性化的设...

飞扬青云
58分钟前
2
0
NCRE考试感想 三级信息安全(下)

时代的变迁 一些学科的兴起,一些学科的没落;一些职业的兴起,一些职业的没落。在2016年,新闻报道中说:国务院取消了百余项职业资格证书。一切都处于变动之中,要找到变化的规律,跟上时代...

志成就
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部