zoukankan      html  css  js  c++  java
  • 可插拔windows服务

    如何实现可插拔的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服务代码了

  • 相关阅读:
    try
    mysql 遇到的问题
    java POI(二)
    Spring/SpringBoot整合QuartZ
    Spring整合QuartZ
    Idea使用指南--实用版
    QuartZ
    Spring Task
    Spring01-模块划分
    国际化、文件上传下载
  • 原文地址:https://www.cnblogs.com/lodestar/p/718615.html
Copyright © 2011-2022 走看看