现在的系统越来越庞大复杂,对系统进行拆分,让各个独立模块各干各的事,已经是现有大型系统普遍采用的解决方案,美其名曰SOA,说的狭窄一点,就是原来是本地调用的,现在变成了远程调用,于是乎,各种远程调用的方案冒出来了,Remoting、WCF、REST等等,这些名词的堆积起来,让开发者有点不知所然,要花很多时间去理解和消化这些概念,而对于真正的业务编码却花不了这么多时间;为何不让这些细节隐藏起来,让远程调用如同本地调用一样方便简单呢?让中间的细节,比如通讯方式是TCP还是HTTP,序列化是SOAP还是JSON,性能效率、负载均衡等等问题,都交给架构师、框架设计师去处理吧,我们只需要关心自己的业务实现就可以,这个愿望很简单吧。
我们设想有这么个服务,我们把它看成是.NET里的接口, 如下代码所示:
3 public interface IClassService
4 {
5 string HelloWorld();
6 }
7 }
这个接口定义在ClassLibrary1.dll中,我们期望这么去调用:
2 using System.Collections.Generic;
3 using System.Text;
4 using ClassLibrary1;
5 using HTB.DevFx.Esb;
6
7 namespace ConsoleApplication2
8 {
9 class Program
10 {
11 static void Main(string[] args) {
12 var svr = ServiceLocator.GetService<IClassService>();
13 Console.WriteLine(svr.HelloWorld());
14 Console.ReadLine();
15 }
16 }
以上代码定义在ConsoleApplication2.exe中。是不是很简单,我们是调用者,没必要关心谁是接口的实现者,交给IoC好了。至于这返回的svr是远程对象还是本地对象,我们更无需关心了。只管调用好了。
当然了,在具体运行时,总该有一个实现者来实现接口吧,但以上代码找不到谁实现了这个接口。我们把实现这个接口的代码定义在CosoleApplication1.exe中,如下:
2 using ClassLibrary1;
3 using HTB.DevFx.Remoting;
4
5 namespace ConsoleApplication1
6 {
7 class Program
8 {
9 static void Main(string[] args) {
10 RemotingHelper.RemotingServiceInitialize();
11 Console.WriteLine("Ready....");
12 Console.ReadLine();
13 }
14 }
15
16 internal class ClassServiceInternal : IClassService
17 {
18 public string HelloWorld() {
19 return DateTime.Now.ToString();
20 }
21 }
看,我们有一个实现,而且是internal的,这里稍微解释下Main函数里做的事情,就是让ClassServiceInternal以服务的形式发布出去,更具体的留待后文解释。
好了,我们现在有实现者了,那怎么让调用者调用我们的实现者呢,总不能让ConsoleApplication2.exe引用ConsoleApplication1.exe吧,再说了,实现类是internal的,引用了也不能直接调用。既然IClassService都已经按服务的方式发布出去了,我们只需要远程调用就可以啦,让IoC帮我们吧,我们期望我们的IoC配置也需要尽量简单,所以在ConsoleApplication2.exe.config中,我们配置如下:
2 <configuration>
3 <configSections>
4 <section name="htb.devfx" type="HTB.DevFx.Config.ConfigSectionHandler, HTB.DevFx.BaseFx" />
5 </configSections>
6
7 <htb.devfx>
8 <objects configSet="{tag:'object'}">
9 <object name="ClassServiceClient" type="ClassLibrary1.IClassService, ClassLibrary1" mapTo="http://localhost:8296/classService.rem" builder="@RemotingObjectBuilder" />
10 </objects>
11 </htb.devfx>
如上配置,我们期望我们的接口IClassService映射到远程服务接口http://localhost:8296/classService.rem上,这个远程地址是ConsoleApplication1.exe发布出去的。很直观很简单。当然,我们可以把它映射成本地实现,比如本地的Mock实现,这样有利于单元测试和同步开发。
以上均得益于基于配置的IoC框架DevFx,DevFx让我们调用服务如此简单(是不是有广告的嫌疑?)
具体原理留待后文讲解。
以上代码下载:测试代码
有关DevFx的更多细节:http://devfx.codeplex.com/