文档章节

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

architect刘源源
 architect刘源源
发布于 2018/01/13 18:29
字数 901
阅读 15
收藏 2

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

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

 

服务定位器

 

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

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

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

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

 

[java] view plain copy

  1. public class ServiceLocator {  
  2.       
  3.     static{  
  4.         //该类加载的时候执行一次  
  5.         Container.init();  
  6.     }  
  7.     public static Object getDao(){  
  8.         return Container.getComponent("dao4Mysql");  
  9. //      return Container.getComponent("dao4Oracle");  
  10.     }  
  11. }  

修改ServiceImpl的查找逻辑:

 

 

[java] view plain copy

  1. import com.tgb.container.ServiceLocator;  
  2. import com.tgb.container.dao.Dao;  
  3. import com.tgb.container.service.Service;  
  4.   
  5. public class ServiceImpl implements Service {  
  6.     // 从服务器定位器查找所需的接口  
  7.     private Dao dao = (Dao) ServiceLocator.getDao();;    
  8.       
  9.     @Override  
  10.     public void serviceMethod() {  
  11.         dao.daoMethod();  
  12.     }  
  13.   
  14. }  

UML类图:

 

        

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

式”管理。

 

控制反转(IoC)

 

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

调用类的对象中。

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

 

修改Service接口:

 

[java] view plain copy

  1. import com.tgb.container.dao.Dao;  
  2.   
  3.   
  4. public interface Service {  
  5.     //增加注入接口的方法  
  6.     public void setDao(Dao dao);  
  7.     public void serviceMethod();  
  8. }  

修改ServiceImpl:

 

 

[java] view plain copy

  1. import com.tgb.container.dao.Dao;  
  2. import com.tgb.container.service.Service;  
  3.   
  4. public class ServiceImpl implements Service {  
  5.     private Dao dao;    
  6.     //依赖注入  
  7.     public void setDao(Dao dao) {  
  8.         this.dao= dao;  
  9.     }  
  10.       
  11.     @Override  
  12.     public void serviceMethod() {  
  13.         dao.daoMethod();  
  14.     }  
  15. }  

修改Container类的初始化方法:

 

 

[java] view plain copy

  1. import java.util.HashMap;  
  2. import java.util.Map;  
  3.   
  4. import com.tgb.container.dao.Dao;  
  5. import com.tgb.container.dao.impl.Dao4MySqlImpl;  
  6. import com.tgb.container.service.Service;  
  7. import com.tgb.container.service.impl.ServiceImpl;  
  8.   
  9. public class Container {  
  10.     private static Map<String, Object> components;  
  11.   
  12.     private Container() {  
  13.     }  
  14.   
  15.     /** 
  16.      * 初始化容器 
  17.      */  
  18.     public static synchronized void init() {  
  19.         if (components == null) {  
  20.             components = new HashMap<String, Object>();  
  21.               
  22.             //写一个读配置文件的类,根据读取的配置文件,反射对应的类  
  23.             //反射好类后进行 依赖管理,往对应的属性上注入相应的类  
  24.               
  25.             Dao dao4Mysql = new Dao4MySqlImpl();  
  26.             components.put("dao4Mysql", dao4Mysql);  
  27.               
  28.             Service service = new ServiceImpl();    
  29.             components.put("service", service);  
  30.               
  31.             //容器维护依赖关系  
  32.             service.setDao(dao4Mysql);  
  33.         }  
  34.     }  
  35.   
  36.     /** 
  37.      * 查找组件 
  38.      *  
  39.      * @param id 
  40.      * @return 
  41.      */  
  42.     public static Object getComponent(String id) {  
  43.         return components.get(id);  
  44.     }  
  45. }  

UML类图:

 

 

        

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

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

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

 

对比

 

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

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

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

 

© 著作权归作者所有

architect刘源源

architect刘源源

粉丝 156
博文 508
码字总数 904778
作品 0
浦东
程序员
私信 提问
spring和springmvc的区别

spring 是一个开源框架,是为了解决企业应用程序开发,功能如下 ◆目的:解决企业应用开发的复杂性 ◆功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能 ◆范围:任何Java应用 ...

明理萝
2018/07/30
0
0
Java程序员从笨鸟到菜鸟之(六十七)细谈Spring(一)spring简介

Spring 是一个开源框架,是为了解决企业应用程序开发复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许您选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。 然而...

长平狐
2012/11/12
72
0
Spring应用学习——IOC

Spring简介 1. Spring的出现是为了取代EJB(Enterprise JavaBean)的臃肿、低效、脱离现实的缺点。Spring致力于J2EE应用的各层(表现层、业务层、持久层)的解决方案,Spring是企业应用开发的...

江左煤郎
2018/11/16
0
0
【第1章 Spring概述与结构】1.1 Spring起源与概述

Rod Johson在2002年编著的《Expert one to one J2EE design and development》一书中,对Java EE正统框架臃肿、低效、脱离现实的种种现状提出了质疑,并积极寻求探索革新之道。以此书为指导思...

陶邦仁
2015/05/15
0
0
控制反转和依赖注入的理解(通俗易懂)

学习过Spring框架的人一定都会听过Spring的IoC(控制反转) 、DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC 、DI这两个概念是模糊不清的,是很难理解的,今天和大家分享网上的一...

小橙子的曼曼
03/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

【redis】spring boot利用redis的Keyspace Notifications实现消息通知

前言 需求:当redis中的某个key失效的时候,更新key对应数据在数据库的状态 1、修改redis.conf 安装的redis服务默认是: notify-keyspace-events "",修改成 notify-keyspace-events Ex; 位置...

时刻在奔跑
4分钟前
0
0
IT基础设施中的人工智能可以改变工作的方式

  如今,减少人工智能的宣传和炒作已成为IT领导者的主要工作。提供有关人工智能在何处以及如何将其添加到IT基础设施的深入指南将会提供帮助。   很多技术提供商正在投入巨资,将人工智能...

琴殇的
5分钟前
0
0
vue cli3创建测试打包环境(通过development、production、alpha指定不同的接口地址)

参考地址 前言:项目一般有开发环境,测试环境,生产环境;vue cli内置有开发和生产环境,可以用process.env.NODE_ENV区分,有时候我们和后台同事需要本地连接调试代码,又需要连接测试环境调...

hkaikai
11分钟前
1
0
360安全浏览器龙芯、飞腾、兆芯版

主页https://browser.360.cn/se/linux/ 龙芯 http://down.360safe.com/gc/browser360-cn-stable-10.0.2001.0-1.mips64el.rpm http://down.360safe.com/gc/browser360-cn-stable_10.0.2001.0......

gugudu
11分钟前
22
0
访问JSP时,浏览器显示为

问题: <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param>......

器石_
15分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部