企业应用微型Windows服务架构
企业应用微型Windows服务架构
背景:质量检测集团企业内部有N多系统,这些系统之间有关联性并相互协作,很多业务需要Windows服务大显身手
举例:客户通过网站下定单 > 企业内部收到客户快递的样品在实验室系统登记 > 实验室系统检测 > 实验室系统出具检测报告 > 客户通过浏览器查看报告
运用Windows服务进行:
报告文件同步 对客户的短信、邮件通知 对内部工作人员进行短信、邮件通知 进行分公司内网与公共服务器数据同步……
以上只是一个例子,实际情况要复杂的多,很多个服务放在一起运行、维护很不方便,混乱不堪,如何通过一种巧妙的方式进行管理、部署、监控,让管理人员可操作性更强呢?博主写了一个小程序来达到上面的要求,请大家指点一二。
技术点:
XML读写 多线程 反射 Windows服务安装卸载脚本思路:
windows服务项目是一个装载服务的容器,它负责配置并调用功能组件 提供一个统一的编程接口,使后续所有的功能组件都需要实现这个接口方便服务容器去调用 植入功能组件:实现以上接口并单独做自己的事情,与其他功能组件互不相干 放到Windows服务容器,配置组件信息(执行间隔,程序集名称,类名等)以上模式有点像一个多媒体播放器程序,自身提供了解析mp3,mp4,wma,rmvb等格式的功能
播放器就是一个装载容器,解析媒体文件格式的组件就相当于插件
当有一种新的媒体格式比如(flv)诞生后,开发者们可以实现播放器提供的接口并解析这种(flv)媒体文件,然后通过配置文件添加到播放器目录即可
当播放器要播放flv的文件,就会去加载解析flv的组件
每一种对媒体格式的解析组件互不影响,这符合松耦合、工厂模式的设计思想
废话说到这里,贴代码:
接口:
1 public interface IRun 2 { 3 void Run(); 4 }
配置文件Config.xml,配置程序集的执行时间间隔,程序集名称,类名
1 <? xml version="1.0" encoding="utf-8" ?> 2 < Configuration > 3 <!-- 4 assembly:程序集名称 5 class:类名 6 method:固定Run(),默认为Run,对应类需要实现接口IRun并实现Run() 7 --> 8 < AssemblyConfig > 9 < Assembly Interval ="30000" Assembly ="FCL.Monitor" Class ="Monitor" /> 10 < Assembly Interval ="30000" Assembly ="FCL.Monitor" Class ="Monitor_Vancl" /> 11 < Assembly Interval ="30000" Assembly ="FCL.Monitor" Class ="CreateNotify" /> 12 < Assembly Interval ="30000" Assembly ="FCL.Monitor" Class ="CreateNotify_Vancl" /> 13 < Assembly Interval ="1000" Assembly ="FCL.Email" Class ="SendEmail" /> 14 </ AssemblyConfig > 15 </ Configuration >
容器加载后需要构造的实体类
1 public class AssemblyInfo 2 { 3 /// <summary> 4 /// 执行间隔 5 /// </summary> 6 public int Interval { get ; set ; } 7 8 /// <summary> 9 /// 程序集名称 10 /// </summary> 11 public string AssemblyName { get ; set ; } 12 /// <summary> 13 /// 类名 14 /// </summary> 15 public string ClassName { get ; set ; } 16 /// <summary> 17 /// 方法名 18 /// </summary> 19 public readonly string MethodName = " Run " ; 20 }
服务启动需要加载已经配置的程序集
1 /// <summary> 2 /// 服务启动 3 /// </summary> 4 /// <param name="args"></param> 5 protected override void OnStart( string [] args) 6 { 7 Log.log.Info(DateTime.Now + " 服务启动 " ); 8 9 // 读取xml配置 10 DataSet ds = new DataSet(); 11 ds.ReadXml(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, " Config.xml " )); 12 DataTable dt = ds.Tables[ 1 ]; 13 List<AssemblyInfo> assemblyInfoList = new List<AssemblyInfo> (); 14 AssemblyInfo assemblyInfo; 15 foreach (DataRow row in dt.Rows) 16 { 17 assemblyInfo = new AssemblyInfo(); 18 assemblyInfo.AssemblyName = row[ " Assembly " ].ToString(); 19 assemblyInfo.ClassName = row[ " Class " ].ToString(); 20 assemblyInfo.Interval = Convert.ToInt32(row[ " Interval " ]); 21 assemblyInfoList.Add(assemblyInfo); 22 23 Log.log.Info(DateTime.Now 24 + " 程序集名称: " + assemblyInfo.AssemblyName 25 + " ,类名: " + assemblyInfo.ClassName 26 + " ,执行间隔: " + assemblyInfo.Interval); 27 } 28 29 // 加载XML程序集配置 30 ExcuteAssembly.ExcuteListAssembly(assemblyInfoList); 31 }
以及相关用线程、反射执行程序集
public class ExcuteAssembly { /// <summary> /// 执行批量程序集 /// </summary> /// <param name="assemblyList"> 程序集集合 </param> public static void ExcuteListAssembly(List<AssemblyInfo> assemblyList) { try { Thread thread; foreach (AssemblyInfo item in assemblyList) { thread = new Thread( new ParameterizedThreadStart(ExcuteSingleAssembly)); thread.IsBackground = true ; thread.Start(item); } } catch (Exception ex) { Log.log.Error(DateTime.Now + " 创建多个线程时: " + ex.Message); } } /// <summary> /// 执行单个程序集 /// </summary> /// <param name="obj"> 程序集 </param> public static void ExcuteSingleAssembly( object obj) { while ( true ) { try { AssemblyInfo assembly = obj as AssemblyInfo; Thread.Sleep(assembly.Interval); Log.log.Debug( " ExcuteSingleAssembly: " + (assembly as AssemblyInfo).AssemblyName); if (assembly != null && assembly is AssemblyInfo) { Assembly a = Assembly.Load(assembly.AssemblyName); // Type规则:命名空间名称=程序集名 Type type = a.GetType(assembly.AssemblyName + " . " + assembly.ClassName); Log.log.Debug( " Type: " + type.ToString()); IRun run = (IRun)Activator.CreateInstance(type); MethodInfo method = type.GetMethod(assembly.MethodName); Log.log.Debug( " MethodInfo: " + method.ToString()); BindingFlags flags = BindingFlags.Public | BindingFlags.Instance; method.Invoke(run, flags, Type.DefaultBinder, null , null ); } } catch (Exception ex) { Log.log.Error(DateTime.Now + " 执行程序集时出错: " + ex.Message); } } } }
以上就是服务容器的核心代码,下面贴一个组件代码
1 /// <summary> 2 /// 监测ERP数据库的单据状态,并生成消息日志 3 /// </summary> 4 public class Monitor : IRun 5 { 6 public void Run() 7 { 8 new DAL.Sys_ApplyFormNotifyLog().CreateNotify(); 9 } 10 }
关于服务的安装运行卸载也写了批处理
安装:
echo 清理原有服务项. . . %SystemRoot%\Microsoft.NET\Framework\v4. 0.30319 \installutil / U FCL.WinService.exe echo 清理完毕,开始安装后台服务. . . %SystemRoot%\Microsoft.NET\Framework\v4. 0.30319 \installutil FCL.WinService.exe echo 服务安装完毕 pause
启动:
echo 启动服务. . . net start FCLService pause
停止:
echo 停止服务. . . net stop FCLService pause
到此结束,程序里有很多需要改进之处,使程序更加灵活、稳定、强壮,请大家多多指点。
标签: windows服务 , 反射
作者: Leo_wl
出处: http://www.cnblogs.com/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息查看更多关于企业应用微型Windows服务架构的详细内容...