java侵入式设计举例_一步步重构容器实现Spring框架——解决容器对组件的“侵入式”管理的两种方案--主动查找和控制反转(九)...

如何让组件不再依赖容器?这篇

博文主要是通过两种解决方案来解决这个问题,最后对比各自的优缺点。

服务定位器

解决方案之一就是使用服务定位器(Service Locator),我们也可以叫主动查找。服务定位器用来封装复杂的查

找逻辑,同时对外开放简单的查找方法,所有组件都可以将查找请求委派给服务定位器。

服务定位器可是一个简单的类,也可以是一种复杂的机制,如JNDI。不同的容器有着不同的查找机制。

下面是一个简单的服务定位器:

public class ServiceLocator {

static{

//该类加载的时候执行一次

Container.init();

}

public static Object getDao(){

return Container.getComponent("dao4Mysql");

//      return Container.getComponent("dao4Oracle");

}

}

修改ServiceImpl的查找逻辑:

import com.tgb.container.ServiceLocator;

import com.tgb.container.dao.Dao;

import com.tgb.container.service.Service;

public class ServiceImpl implements Service {

// 从服务器定位器查找所需的接口

private Dao dao = (Dao) ServiceLocator.getDao();;

public void serviceMethod() {

dao.daoMethod();

}

}

UML类图:

8c17a92cb7576a848e8da6e748863204.png

原先由ServiceImpl到Container的依赖线上添加了ServiceLocator,组件不再直接依赖于容器,实现了“非侵入

式”管理。

控制反转(IoC)

解决方案之二就是使用控制反转,我们将控制权交给容器,在运行期才由容器决定将具体的实现动态的“注入”到

调用类的对象中。

Ioc是一种通用的设计原则,DI(依赖注入)则是具体的设计模式。依赖注入有三种方式,我们使用的是Setter注入。

修改Service接口:

import com.tgb.container.dao.Dao;

public interface Service {

//增加注入接口的方法

public void setDao(Dao dao);

public void serviceMethod();

}

修改ServiceImpl:

import com.tgb.container.dao.Dao;

import com.tgb.container.service.Service;

public class ServiceImpl implements Service {

private Dao dao;

//依赖注入

public void setDao(Dao dao) {

this.dao= dao;

}

public void serviceMethod() {

dao.daoMethod();

}

}

修改Container类的初始化方法:

import java.util.HashMap;

import java.util.Map;

import com.tgb.container.dao.Dao;

import com.tgb.container.dao.impl.Dao4MySqlImpl;

import com.tgb.container.service.Service;

import com.tgb.container.service.impl.ServiceImpl;

public class Container {

private static Map components;

private Container() {

}

/**

* 初始化容器

*/

public static synchronized void init() {

if (components == null) {

components = new HashMap();

//写一个读配置文件的类,根据读取的配置文件,反射对应的类

//反射好类后进行 依赖管理,往对应的属性上注入相应的类

Dao dao4Mysql = new Dao4MySqlImpl();

components.put("dao4Mysql", dao4Mysql);

Service service = new ServiceImpl();

components.put("service", service);

//容器维护依赖关系

service.setDao(dao4Mysql);

}

}

/**

* 查找组件

*

*/

public static Object getComponent(String id) {

return components.get(id);

}

}

UML类图:

b5c0559d1627e5e829d2103bfa23a6f8.png

由ServiceImpl到Container的依赖线可以直接抹掉了!

Setter注入易于使用,但是会有安全问题。第一次注入之后,有可能再一次调用setter方法,改变了原有的依赖。

这种对依赖的无意修改会带来无法预料的后果。所以需要有安全检查机制。

对比

解决组件不再依赖容器,我们使用了两种方案:服务定位器和控制反转。

1、使用服务定位器查找组件,这是一种主动查找的行为。这种查找有一个缺点:组件需要知道如何查找资源。组件和容器依赖变成了组件和服务定位器的依赖。

2、然后,我们使用了控制反转,这是一种被动查找的行为。容器主动将资源推送给组件,组件则以一种合适的方式来接受资源。反转资源获取方向,这就是大名鼎鼎的Ioc(控制反转)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值