接上文
http://sarin.iteye.com/blog/593207
public interface Injectable {
public void inject(Map<String,Object> components);
}
public class ChartService implements Injectable {
private ChartGenerator chartGenerator;
public void inject(Map<String, Object> components) {
chartGenerator = (ChartGenerator) components.get("chartGenerator");
}
… … …
}
public class Container {
… … …
public Container() {
components = new HashMap<String, Object>();
ChartGenerator chartGenerator = new PieChartGenerator();
components.put("chartGenerator", chartGenerator);
ChartService chartService = new ChartService();
components.put("chartService", chartService);
chartService.inject(components);
}
… … …
}
接口注入的缺点非常明显,就是组件必须实现特定接口,而这个接口是特定于容器的,所以组件对容器产生依赖,一旦脱离容器,组件不能重用。这就是“侵入式”的设计,容器“侵入式”注入组件,由于这个原因,绝大部分IoC容器不支持接口注入。
构造方法注入,这是大部分IoC容器支持的方式,使用构造方法注入时,容器通过显式定义的构造方法传入参数,此时Java编译器不会给这个类增加默认的构造方法了,这在使用时要注意,一般是人为定义一个默认的构造方法。使用构造方法注入时,我们不会遗漏任何的依赖,依赖一旦注入将不能被更改,不会因为无意修改而造成问题。
public class ChartService {
private ChartGenerator chartGenerator;
public ChartService() {// 默认构造方法
}
public ChartService(ChartGenerator chartGenerator) {// 重载构造方法
this.chartGenerator = chartGenerator;
}
… … …
}
public class Container {
… … …
public Container() {
… … …
ChartService chartService = new ChartService(chartGenerator);
components.put("chartService", chartService);
}
… … …
}
但是构造方法也有自己的局限,setter方法注入时类中的setXXX()方法名会告诉你正在注入的依赖。使用构造方法时,只能通过参数的位置来确定参数。而且组件的参数过多时,那么构造方法的参数列表将会非常冗余。
setter方法注入,这种方法非常易于使用,也很简单,绝大多数Java IDE也都支持自动生成setter方法,所以这是一种非常流行的方法。
public class ChartService {
private ChartGenerator chartGenerator;
public void setChartGenerator(ChartGenerator chartGenerator) {
this.chartGenerator = chartGenerator;
}
… … …
}
public class Container {
… … …
public Container() {
… … …
ChartService chartService = new ChartService();
chartService.setChartGenerator(chartGenerator);
components.put("chartService", chartService);
}
… … …
}
setter方式的注入也存在一些小问题,如果组件使用者忘记给组件注入它所需的依赖,将会导致NullPointerException异常,这个异常的查找是非常麻烦,因为它埋藏的很深。不过Spring的IoC容器在组件初始化时提供对特定依赖的检查。同时,setter注入的另外一个缺点就是安全性,必须对此做出处理,因为在第一次注入之后除非自己实现安全机制来阻止再次调用setter方法,否则依赖仍然可能会因为setter方法的调用而被二次修改,这种无意的修改将会带来无法预知的后果,而它也是埋藏很深的一种BUG。
至此我们已经彻底理解依赖注入的原理了,但是代码都是写死后来做测试的,下面我们使用XML文件来进行动态依赖注入。
所用依赖注入方式为setter注入。不使用properties是因为java.util.Properties类继承了HashTable类,而HashTable是无序的,而依赖注入是有顺序的,那么使用properties文件就可能产生问题。
实验时需要Apache Commons组件Beanutils和Logging,还有DOM4J来解析XML。DOM4J是也是Hibernate进行配置文件解析所依赖的第三方类库,使用方便。
package v5;
import java.io.File;
import java.util.*;
import org.apache.commons.beanutils.PropertyUtils;
import org.dom4j.*;
import org.dom4j.io.SAXReader;
public class Container {
private Map<String, Object> components;
public Container() {
components = new HashMap<String, Object>();
try {
File f = new File("src/v5/components.xml");
Document document = new SAXReader().read(f);
Element root = document.getRootElement();
Element component;
Iterator iterator = root.elementIterator("component");
Map<String, String> properties = new TreeMap<String, String>();// TreeMap是有序的,不会造成依赖注入时顺序颠倒
while (iterator.hasNext()) {// 遍历节点,获得所需元素的值
component = (Element) iterator.next();
properties.put(component.elementText("key"), component
.elementText("value"));
}
System.out.println(properties);
for (Map.Entry entry : properties.entrySet()) {
String key = (String) entry.getKey();
String value = (String) entry.getValue();
processEntry(key, value);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void processEntry(String key, String value) throws Exception {
String[] parts = key.split("\\.");
if (parts.length == 1) {// 新组件定义
Object compnent = Class.forName(value).newInstance();
components.put(parts[0], compnent);
} else {// 依赖注入
Object component = components.get(parts[0]);
Object reference = components.get(value);
PropertyUtils.setProperty(component, parts[1], reference);
}
}
public Object getComponent(String id) {
return components.get(id);
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<components>
<component>
<key>chartGenerator</key>
<value>v5.PieChartGenerator</value>
</component>
<component>
<key>chartService</key>
<value>v5.ChartService</value>
</component>
<component>
<key>chartService.chartGenerator</key>
<value>chartGenerator</value>
</component>
</components>
按顺序注入依赖,不能颠倒顺序。
至此,我们模拟了依赖注入的整个过程,那么后面对Spring的学习效率将会大幅提高。一家之言,仅供参考。希望对学习者有用。(全篇完)
- 大小: 14.5 KB
- 大小: 12.3 KB
- 大小: 13.6 KB
- 大小: 18.4 KB
分享到:
相关推荐
### C# 依赖注入 控制反转 #### 一、IoC(控制反转)简介 IoC,即"Inversion of Control"(控制反转),是软件工程领域的一个重要概念,特别是面向对象编程中的一个关键设计原则。从字面上理解,IoC指的是程序运行...
### Spring2.5 IoC(控制反转)容器详解:容器与Bean #### 一、Spring IoC 容器概述 Spring IoC(Inversion of Control,控制反转)容器是Spring框架的核心组件之一,用于管理对象的生命周期以及依赖关系。通过...
Spring.NET 控制反转(Inversion of Control,英文缩写为IoC),也叫依赖注入(Dependency Injection)。我个人认为控制反转的意思是依赖对象(控制权)发生转变,由最初的类本身来管理依赖对象转变为IoC框架来管理...
### Spring自学笔记-Ioc(控制反转)容器 #### 一、Spring框架简介 Spring框架是一个开源的Java平台,用于构建企业级应用。它提供了一种轻量级的方式来管理应用程序的各种组件和服务,使得开发者能够更容易地构建...
通过上述介绍,我们可以看出Spring IOC控制反转的核心思想是将对象的创建和管理交给了Spring容器,从而实现了组件间的解耦。这种方式极大地提高了代码的可维护性和扩展性,是现代Java开发中不可或缺的一部分。
Spring的IOC容器引入了新的解决方案,它接管了对象的创建和管理,这就是控制反转。 ### IOC容器 Spring的IOC容器,如`BeanFactory`和`ApplicationContext`,是管理对象的核心组件。它们为组件提供运行环境,负责...
控制反转是一种设计模式,它改变了传统应用程序中对象获取依赖的方式,将对象创建和组装的过程交给容器来管理,从而使代码更加灵活、易于测试和维护。 在Spring框架中,控制反转主要通过两种方式实现:构造器注入和...
在软件开发中,控制反转(Inversion of Control,简称IoC)是一种设计原则,它将对象的创建和管理权从代码中剥离出来,转交给一个外部容器(如Spring框架)。通过这种方式,开发者可以专注于业务逻辑,而不是对象的...
在编程领域,控制反转(Inversion of Control,简称IoC)是一种设计模式,它将对象的创建和管理责任从应用程序转移到框架或容器中。在Java编程中,IoC通过依赖注入(Dependency Injection,DI)来实现,使得组件之间...
控制反转的核心理念是将对象的创建和管理权交给一个外部容器,而不是由对象自身负责。在ASP.NET MVC4中,这一概念主要通过依赖注入(Dependency Injection,简称DI)实现。 **1. 依赖注入 (DI)** 依赖注入是IoC的...
控制反转(IOC)意味着应用程序不再直接创建对象,而是将对象的创建和管理交给一个外部容器(在Spring中就是IOC容器)。这样,开发者可以更专注于业务逻辑,而不是对象的生命周期。依赖注入(Dependency Injection,...
在InversifyJS中,控制反转是核心概念。它将对象的创建和管理责任从代码逻辑中分离出来,交由容器负责。这样,当需要一个依赖时,而不是手动创建它,容器会根据配置自动提供。这降低了类之间耦合度,因为类不再直接...
控制反转是一种设计原则,它的主要思想是将对象的创建和管理权交给容器,而不是由对象自身负责。在传统的编程模式中,一个对象需要另一个对象时,通常会自行创建或寻找。而在IOC中,对象不再直接创建依赖对象,而是...
控制反转的主要思想是将对象之间的依赖关系从代码内部转移到外部容器,从而使代码更加灵活、可测试和可维护。在这个例子中,我们将探讨如何在C#中实现IoC。 首先,让我们理解IoC的基本原理。传统的程序设计中,类A...
在Android开发中,“控制反转”(Inversion of Control,简称IOC)是一种设计模式,它将对象的创建和管理权从代码本身转移到一个外部容器,如依赖注入框架。本篇文章主要探讨的是Android中如何实现和应用控制反转,...
在软件开发中,IoC(Inversion of Control,控制反转)是一种设计模式,它将对象的创建和管理责任从代码中剥离出来,交由一个容器来处理。Spring框架是Java平台上的一个核心组件,其核心特性就是依赖注入...
### IOC控制反转在代码中的体现 #### 一、IOC(Inversion of Control)概念解析 IOC,即控制反转,是一种设计思想,在Java开发领域中,它主要被用来消除程序之间的依赖性,使得类的设计更加灵活。传统的编程模式下...
在书中,作者们将这二十三种设计模式分成了三类,分别是创建型模式、结构型模式和行为型模式。 创建型模式包含了: 工厂方法模式( Factory Method ) 抽象工厂模式( Abstract Factory ) 单例模式( Singleton ...