现在的位置: 首页 > 综合 > 正文

可插拔windows服务

2012年01月01日 ⁄ 综合 ⁄ 共 2977字 ⁄ 字号 评论关闭

如何实现可插拔的windows服务
关于windows服务的创建相关资源很多,园子里面也有很多这样的文章。
整理了一下相关blog如下,
http://www.cnblogs.com/wuxilin/archive/2006/06/04/416838.html
http://www.cnblogs.com/wujm/archive/2005/05/12/154369.html
http://www.cnblogs.com/caca/archive/2005/02/25/109028.html
http://www.cnblogs.com/laiwen/archive/2005/08/21/219590.html

归纳一下步骤大概如下:
1.创建服务:
1.1我们应该创建windows服务类型的project,IDE会自动从serviceBase类继承一个类出来,在这个类里面有on_star和on_stop两个方法,可以在里面写入启动逻辑和停止逻辑
在设计视图下我们可以修改service的属性
Autolog                 是否自动写入系统的日志文件
CanHandlePowerEvent     服务时候接受电源事件
CanPauseAndContinue     服务是否接受暂停或继续运行的请求
CanShutdown             服务是否在运行它的计算机关闭时收到通知,以便能够调用 OnShutDown 过程
CanStop                 服务是否接受停止运行的请求
ServiceName             服务名
1.2选择服务组件,并切换到设计模式,右键->Add Installer,生成安装文件。安装文件中的属性修改可以参考下面的内容:
projectInstall参数修改Account(指定用户还是使用本地系统用户)
ServiceInstall参数修改:
描述名:Description,
显示名:DisplayName,
ServiName:服务名,要和刚才建立的服务名一一对应才行
StartType:(Manual:服务安装后,必须手动启动.Automatic:每次计算机重新启动时,服务都会自动启动;Disabled:服务无法启动)

2安装
安装服务要使用微软提供的工具InstallUtil,这个工具在c:/windows/wicrosoft.net/framework/[version]中
使用InstallUtil 安装,使用InstallUtil /u 反安装服务

如果还有什么可以参考刚才说的那几个blog,ok一切都很简单。但是如果要做为一个企业级的应用,往往会有别的场景需求,下面说一下我曾碰到的场景要求
1.我们的windows服务可能不止满足一种业务逻辑,比如:如果你的机器安装了oracle的话,就会有OracleService服务,我们启动数据库的时候可以只是启动tns服务和OracleService服务就可以了,但是实际上启动OracleService服务的同时会启动好几个服务,例如:DBWR(数据文件写入),LGWR(日志文件写入),SMON(系统监护),PMON(用户进程监),CKPT(检查点,同步数据文件,日志文件,控制文件等)。有时为了性能的考虑,一个服务也可能要多线程的运行业务逻辑。比如一个导入文件的数据接口服务,如果数据量非常大就要这样考虑。一般如果执行多个任务,可以有两种方法:1.开多个线程;2.在一个线程中顺序进行(可以加上时间控制)。我觉得这里最灵活的方法是用.net本省的多线程支持来解决。
2.要能在不改变系统结构的情况下,可以非常快速的支持新的服务要求。这说明我们在onstar方法中不能写入相关类的处理逻辑,必须要用某种方法解耦才行。

实现方法:
参考下面的类图

servcive类和具体的业务实现类解耦,我们可以使用工厂模式生成业务逻辑类,每个业务逻辑类启动在一个新的线程中,在.net中工厂模式可以用反射非常方便的实现,这块代码如下:

typeInfo = node.Attributes["type"].Value;
                    Type type 
= Type.GetType(typeInfo);
                    IService instance 
= (IService)Activator.CreateInstance(type);
                    
//初始化服务
                    instance.Initialize(node);
                    instanceArray.Add(instance);

                    
//在新线程中运行服务,每个服务使用相同的安全上下文
                    ThreadStart ts = new ThreadStart(instance.Start);
                    Thread t 
= new Thread(ts);
                    t.Start();

从配置文件中读出需要加载的业务逻辑类,实例化后用ThreadStart调用其中的Start方法,启动新线程。这里对配置文件的读取如果要求比较高可以采用Enterprise Libary的Login block来做。
在OnStop方法中调用每个类的Stop方法,如果想对每个Stop方法异步调用,可以用delegate封装接口的Stop方法用
BeginInvoke方法实现异步调用

  foreach (object o in instanceArray)
   
{
    
try
    
{
     IService service 
= (IService)o;
     
if (service !=null)
     
{
            
//异步调用每个服务的stop方法来停止业务组件
      OnStopDelegate osd = new OnStopDelegate(service.Stop);
      osd.BeginInvoke(
null,null);
     }

    }

    
catch (Exception ex)
    
{
     
//
    }

   }

这样,整个windows服务就实现了,这里还有个额外的好处是可以热部署,即不需要删除已经部署的windows服务,将新的DLL覆盖将以前的DLL覆盖,修改*.exe.config文件并重新启动就可以了。其实我觉得停止服务,重新编译部署后在启动服务花费的时间可能比这样还少些。

关于调试:
windows服务常用的调试方法是用调试->附加到进程的方法。
选择显示所有用户进程,我们已经部署并启动的windows服务进程就会出现,并跳到我们设置好的断点处。但是这样对service中的onstart部分调试比较麻烦。我还是推荐创建一个porjec做为调试用,这里面可以写onstart部分的代码,代码不多,非常方便。大家就可以象调试普通windows程序一样调试这windows服务代码了

 

抱歉!评论已关闭.