在Java社区有一股使用轻量级容器来帮助组装不同项目的组件、集成到一个有凝聚力的应用程序的热潮。
这些底层容器有一种普遍的模式去展示他们如何装配组件,他们提出一个概念,名为“控制反转”(Inversion of Control)。
接下来我们深入挖掘下这个模式在“依赖注入”(Dependency Injection)怎么运作的,并且跟服务定位器进行对比。
组件和服务
我说的使用组件意味着,很多软件能自由的使用它,不需改变,因为这个组件已经不受作者的控制。
当我们在外部系统中使用的时候,服务类似组件。
唯一的不同点是我期望在本地使用组件(eg jar file,assembly,dll,or source inport)。
服务通过远程接口来远程调用,可以同步或者异步操作。(eg web service, messaging system, RPC, or socket.)
依赖注入
injector
分为三种类型:构造器注入、setter注入、接口注入。
1 构造器:
class MovieLister...
public MovieLister(MovieFinder finder) {
this.finder = finder;
}
2 setter:
class MovieLister...
private MovieFinder finder;
public void setFinder(MovieFinder finder) {
this.finder = finder;
}
setter的xml配置
<beans>
<bean id="MovieLister" class="spring.MovieLister">
<property name="finder">
<ref local="MovieFinder"/>
</property>
</bean>
</beans>
3 接口:
public interface InjectFinder {
void injectFinder(MovieFinder finder);
}
class MovieLister implements InjectFinder
public void injectFinder(MovieFinder finder) {
this.finder = finder;
}
服务定位器
依赖注入最主要的好处是移除了MovieLister和MovieFinder的implementation(实现)上的依赖。但这并不是唯一的方法,另一种方法是服务定位器。
class ServiceLocator...
private static ServiceLocator soleInstance;
public static void load(ServiceLocator arg) {
soleInstance = arg;
}
private Map services = new HashMap();
public static Object getService(String key){
return soleInstance.services.get(key);
}
public void loadService (String key, Object service) {
services.put(key, service);
}
class Tester...
private void configure() {
ServiceLocator locator = new ServiceLocator();
locator.loadService("MovieFinder", new ColonMovieFinder("movies1.txt"));
ServiceLocator.load(locator);
}
class MovieLister...
MovieFinder finder = (MovieFinder) ServiceLocator.getService("MovieFinder");
依赖注入对于服务定位器来说是一种备选方案。服务定位器因为它的直接行为而有些许优势,但是如果你在很多应用中创建classes的时候,依赖注入是一种更好的选择。
思考:
1.Service Locator vs Dependency Injection
2.Constructor versus Setter Injection
3.Code or configuration files
4.Separating Configuration from Use