三、基于配置文件和Reflection的工厂模式

为了消除MainApp对其它组件的依赖性,我们引入工厂模式,并且根据配置文件指定的装配规程,利用.net提供的反射技术完成对象的组装工作。本部分代码仅仅提供一种功能演示,如果实际应用仍需进一步完善(建议使用一些成型的Ioc框架,例如Spring.net或Castle等)。经过改造后的系统,组件间依赖关系如下图:

可以看出这次实现了真正的“针对接口编程”。所有的组件只依赖于接口。MainApp所需的对象是由工厂根据配置文件动态创建并组装起来的。当系统需求发生变化时,只需要修改一下配置文件就可以了。而且MainApp、SayHello和HelloGenerator之间不存在任何的依赖关系,实现了松耦合。

这是如何实现的呢?我们首先要能够解析配置文件中的信息,然后建立包含相关信息的对象。最后根据这些信息利用反射机制完成对象的创建。首先我们看一下配置文件所包含的内容:

<?xml version="1.0" encoding="utf-8" ?>
<configuration><configSections><sectionGroup name="IocInCSharp"><section name="objects" type="IocInCSharp.ConfigHandler, MainApp" /></sectionGroup></configSections><IocInCSharp><objects><object name="SayHello" assembly="SayHello.dll" typeName="IocInCSharp.SayHello"><property name="HelloGenerator" assembly="HelloGenerator.dll" typeName="IocInCSharp.CnHelloGenerator"></property></object></objects></IocInCSharp>
</configuration>

从中我们可以看出,我们实现了一个IocInCSharp.ConfigHandler类,用来处理配置文件中 IocInCSharp\objects结点中的内容。ConfigHandler类将根据该结点下的内容处理并创建一ConfigInfo对象(关于 ConfigInfo、ObjectInfo以及PropertyInfo的代码可自行查看源代码,这里就不再赘述)。ConfigHandler类的代码实现如下:

using System;
using System.Configuration;
using System.Xml;
namespace IocInCSharp
{public class ConfigHandler:IConfigurationSectionHandler{public object Create(object parent, object configContext, System.Xml.XmlNode section){ObjectInfo info;PropertyInfo propInfo;ConfigInfo cfgInfo = new ConfigInfo();foreach(XmlNode node in section.ChildNodes){info = new ObjectInfo();info.name = node.Attributes["name"].Value;info.assemblyName = node.Attributes["assembly"].Value;info.typeName = node.Attributes["typeName"].Value;foreach(XmlNode prop in node){propInfo = new PropertyInfo();propInfo.propertyName = prop.Attributes["name"].Value;propInfo.assemblyName = prop.Attributes["assembly"].Value;propInfo.typeName = prop.Attributes["typeName"].Value;info.properties.Add(propInfo);}cfgInfo.Objects.Add(info);}return cfgInfo;}}
}

通过ConfigHandler的解析,我们最终得到一个ConfigInfo实例,Factory就是根据这个实例中所包含的配置信息,利用反射技术对所需对象生成并组装的。SayHelloFactory的代码如下:

using System;
using System.IO;
using System.Configuration;
using System.Reflection;
namespace IocInCSharp
{public class SayHelloFactory{public static object Create(string name){Assembly assembly;object o = null;object p;string rootPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar;ConfigInfo cfgInfo = (ConfigInfo)ConfigurationSettings.GetConfig("IocInCSharp/objects"); ObjectInfo info = cfgInfo.FindByName(name);if(info != null){assembly = Assembly.LoadFile(rootPath + info.assemblyName);o = assembly.CreateInstance(info.typeName);Type t = o.GetType();for(int i=0; i<info.properties.Count; i++){               PropertyInfo prop = (PropertyInfo)info.properties[i];assembly = Assembly.LoadFile(rootPath + prop.assemblyName);p = assembly.CreateInstance(prop.typeName);t.InvokeMember(prop.propertyName, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, null, o, new Object[] {p});}}return o;}}
}

在上面这段代码中,重点注意三条命令的使用方法:

assembly = Assembly.LoadFile(rootPath + prop.assemblyName);
p = assembly.CreateInstance(prop.typeName);
t.InvokeMember(prop.propertyName, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, null, o, new Object[] {p});

Assembly.LoadFile()用于将外部文件装载进来;assembly.CreateInstance()根据装载进来的程序集创建一指定类型的对象;t.InvokeMember(prop.propertyName, ........BindingFlags.SetProperty, null, o, new Object[] {p})利用反射机制对创建出来的对象设置属性值。

我们的Factory就是利用这种方式根据配置文件动态加载程序集,动态创建对象并设置属性的。有了这个Factory,MainApp中的内容就很简单了:

using System;
namespace IocInCSharp
{public class MainApp{public static void Main(){ISayHello sayHello = (ISayHello)SayHelloFactory.Create("SayHello");if(sayHello != null)sayHello.SayHelloTo("zhenyulu");elseConsole.WriteLine("Got an Error!");}}
}

现在,MainApp只依赖于接口,不再依赖于其它组件,实现了松耦合。在本例子中,大家可以尝试将配置文件中的IocInCSharp.CnHelloGenerator更改为IocInCSharp.EnHelloGenerator,看看是否输出内容由中文变为了英文。这便是“注入”的效果。

从上面这个例子我们可以看出,通过自定义配置文件和.net中的Reflection技术,我们自己就可以开发Ioc应用,根据配置文件的信息自行组装相应的对象。但是Reflection编程的技术门槛还是比较高的,并且在实际应用中配置文件的格式、Handler的设计都不是象上面代码那样的简单。不过幸好我们现在有很多的Ioc容器可供选择,它们都提供了完整的依赖注入方式,并且比自己写代码更加成熟、更加稳定。使用这些框架可以让程序员在三两行代码里完成“注入”工作。在我们下一个案例中,我们将使用Spring.net实现依赖注入。我们会发现仅仅添加几行代码并更改一下配置文件就可轻松实现依赖注入。(待续)

转载于:https://www.cnblogs.com/kevin-wang/archive/2010/04/29/1723459.html

你真的了解Ioc与AOP 吗?(2)相关推荐

  1. 再品Spring Ioc 和 Aop

    文章目录 Spring好处 IOC 基于XML和基于注解开发 基于XML开发 基于注解开发 配置类 扫包+注解 依赖注入 AOP 写在前面,这篇文章写的时候我的SSM已经学过一遍了,回头来看真的受益匪 ...

  2. 面试官:谈谈你对IOC和AOP的理解及AOP四种实现方式

    目录 一.IOC与AOP介绍 二.实现AOP的四种方式 方式1:基于经典代理来实现 方式2:使用Spring AOP的API接口 方式3:自定义类来实现AOP 方式4:基于注解实现 一.IOC与AOP ...

  3. BeanPostProcessor —— 连接Spring IOC和AOP的桥梁

    之前都是从大Boss的视角,来介绍Spring,比如IOC.AOP. 今天换个视角,从一个小喽啰出发,来加深对Spring的理解. 这个小喽啰就是, BeanPostProcessor (下面简称 B ...

  4. 自己动手实现的 Spring IOC 和 AOP - 下篇

    1. 背景 本文承接上文,来继续说说 IOC 和 AOP 的仿写.在上文中,我实现了一个很简单的 IOC 和 AOP 容器.上文实现的 IOC 和 AOP 功能很单一,且 IOC 和 AOP 两个模块 ...

  5. 自己动手实现的 Spring IOC 和 AOP - 上篇

    1. 背景 我在大四实习的时候开始接触 J2EE 方面的开发工作,也是在同时期接触并学习 Spring 框架,到现在也有快有两年的时间了.不过之前没有仿写过 Spring IOC 和 AOP,只是宏观 ...

  6. Spring 原理初探——IoC、AOP

    前言 众所周知, 现在的 Spring 框架已经成为构建企业级 Java 应用事实上的标准了,众多的企业项目都构建在 Spring 项目及其子项目之上,特别是 Java Web 项目. Spring ...

  7. spring aop 必须的包 及里面用到的东西_Spring 原理初探——IoC、AOP

    前言 众所周知, 现在的 Spring 框架已经成为构建企业级 Java 应用事实上的标准了,众多的企业项目都构建在 Spring 项目及其子项目之上,特别是 Java Web 项目. Spring ...

  8. 我们到底为什么要用 IoC 和 AOP

    作为一名 Java 开发,对 Spring 框架是再熟悉不过的了.Spring 支持的控制反转(Inversion of Control,缩写为IoC)和面向切面编程(Aspect-oriented ...

  9. Dubbo的SPI机制对比传统的SPI做了哪些改进?Dubbo的IOC和AOP

    文章目录 1. JAVA的SPI机制 2. Dubbo的SPI机制 3. Dubbo的SPI源码解析 3.1 获取接口对应的 ExtensionLoader 3.2 根据入参的http获取对应的htt ...

最新文章

  1. TCP通过滑动窗口和拥塞窗口实现限流,能抵御ddos攻击吗
  2. Flume与Kafka整合案例详解
  3. 洛克菲勒的逆商:如何在逆境中转换思维走向成功
  4. springboot+dubbo
  5. 微信小程序蓝牙控制开门
  6. 关于周报的写法和原则
  7. 能装linux的嵌入式,试试一张软盘可装下Linux(嵌入式Linux)
  8. Mesh(802.11s)组网 — 基于OpenWRT路由器
  9. 2016 年度码云热门项目排行榜 TOP 50
  10. 30.1lvs-adm与ipvsadm命令
  11. 无线射频专题《射频单位,功率单位与相对单位,瓦特,毫瓦,分贝,dBi,dBd,dBm》
  12. 一图读懂JVM架构解析
  13. 数据可视化echarts介绍
  14. 用python画股票分时图 github_GitHub - DogeWatch/stock: stock,股票系统。使用python进行开发。...
  15. linux tail命令语法
  16. TFT液晶屏驱动移植
  17. 用QRCode.js制作二维码解析器(qrcode.decode方法解析二维码)
  18. 乔姆斯基文法分类【0型1型2型3型文法】
  19. WinRAR 6.01 官方版
  20. RFID标签打印机在加工制造业中的应用

热门文章

  1. 同步/异步移动文件列表框选中的文件
  2. 谷歌fuchsiaos和华为鸿蒙,华为鸿蒙最大的对手现身!谷歌正式推送Fuchsia OS,或替代安卓...
  3. php图片截取后缀,PHP抓取远程图片(含不带后缀的)教程详解
  4. linux命令 重定向%3e,linux输出信息调试信息重定向
  5. 使用post访问不到接口_Postman工具使用说明
  6. access exex控制pc_ownCloud/Nextcloud文件访问控制(Files Access Control)
  7. hadoop学习5 搭建storm集群
  8. 卡通驱动项目ThreeDPoseTracker——关键点平滑方案解析
  9. 王之泰201771010131《面向对象程序设计(java)》第九周学习总结
  10. 2.自定义变量调节器