Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 560|回复: 0

快速搭建多线程Windows服务解决方案

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-7-9 13:32:10 | 显示全部楼层 |阅读模式

    一、引言

           在软件开发过程中windows服务有的时候非常有用,用于同步数据,发送邮件,宿主WF引擎服务等,但是快速搭建一个好用多线程进行多任务处理的程序往往是一个项目必须考虑的问题。自己在项目中也经常碰到类似的问题,但是一直没有做过这方面总结,每次需要相关windows服务,也重头写一次。自己几乎没有写博客的习惯,前不久看到博客园中有篇关于windows服务的框架写的非常好(抱歉,当时看完以后忘记收藏),感觉自己这些年对它也有一定的认识,但是很少拿出来和大家分享。其实大家都知道通过分享才能找到问题并能提高代码的质量。经过国庆期间的初步整理一个windows服务快速实现的解决方案终于调试通过,当然里面也有一定的问题,希望大伙能指出,谢谢。

    二、通用Windows服务接口

           定义ICommand作为windows service服务接口,所有自定义的服务都应实现ICommand

            

    三、定义WindowsServiceItem对象与WindowsServiceItemCollection集合

          服务的每个任务对应一个WindowsServiceItem,一个服务对应多个任务这样定义WindowsServiceItemCollection集合进行维护每个任务。其实WindowsServiceItem中实现了WindowsTimer周期属性,Type为自定义服务的类型.这里只是简单的对象定义大伙应该一看就明白。

        

    以下是WindowsTimer的定义.

    public class WindowsTimer : IDisposable
        {
            /// <summary>
            /// 周期任务描述
            /// </summary>
            public string Description = string.Empty;
    
            /// <summary>
            /// 时钟周期控件
            /// </summary>
            public Timer Timer = new Timer();
    
            /// <summary>
            /// 是否准备好了可以接受下一个周期的任务
            /// </summary>
            public bool Prepared = true;
    
            /// <summary>
            /// Windows服务的时间控件异常回调委托
            /// </summary>
            public WindowsServiceTimerExceptionCallBack CallBack;
    
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="description">周期任务描述</param>
            /// <param name="interval">执行周期间隔毫秒数</param>
            public WindowsTimer(string description, double interval)
            {
                Description = description;
                Timer.Interval = interval;
                Timer.Enabled = false;
            }
    
            #region IDisposable Members
    
            /// <summary>
            /// 析构函数
            /// </summary>
            ~WindowsTimer()
            {
                Dispose(false);
            }
    
            /// <summary>
            /// 
            /// </summary>
            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
    
            /// <summary>
            /// 
            /// </summary>
            /// <param name="disposing"></param>
            protected virtual void Dispose(bool disposing)
            {
                if (disposing)
                {
                    if (Timer != null)
                    {
                        Timer.Dispose();
                    }
                }
            }
    
            #endregion
        }
    View Code

    四、快速搭建Windows服务核心Windows服务类

          该类继承 System.ServiceProcess.ServiceBase重写相关的基类方法。在此之前定义两个默认Command:WindowsServiceDefaultCommand和WindowsServiceEmptyCommand

        

      核心WindowsService代码如下:

    [Serializable]
        public class WindowsService : System.ServiceProcess.ServiceBase
        {
            private bool _fHasInitServerRemotingObject;
            private readonly object _fHasInitServerRemotingObjectLock = new object();
    
            private readonly WindowsServiceItemCollection _fTimerServices = new WindowsServiceItemCollection();
    
            private readonly object _fTimerServiceObjectsLock = new object();
            private readonly Dictionary<Type, ICommand> _fTimerServiceObjects = new Dictionary<Type, ICommand>();
    
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="timerServices"></param>
            public WindowsService(WindowsServiceItemCollection timerServices)
            {
                if (timerServices != null)
                {
                    foreach (WindowsServiceItem item in timerServices)
                    {
                        _fTimerServices.Add(item);
                    }
                }
            }
    
            /// <summary>
            /// 服务启动执行的操作
            /// </summary>
            /// <param name="args"></param>
            protected override void OnStart(string[] args)
            {
                if (_fTimerServices.Count == 0)
                {
                    var wsiEmpty = new WindowsServiceItem
                        {
                            WindowsTimer = new WindowsTimer("默认的一个Command的轮询周期,设置为5分钟。", 300000),
                            CommandType = typeof (WindowsServiceEmptyCommand)
                        };
                    _fTimerServices.Add(wsiEmpty);
                }
                
                var wsi = new WindowsServiceItem
                    {
                        WindowsTimer = new WindowsTimer("默认的一个Command的轮询周期,设置为5秒钟。", 5000),
                        CommandType = typeof (WindowsServiceDefaultCommand)
                    };
                _fTimerServices.Add(wsi);
    
               
    
                foreach (WindowsServiceItem kvp in _fTimerServices)
                {
                    kvp.WindowsTimer.Timer.Elapsed -= Timer_Elapsed;
                    kvp.WindowsTimer.Timer.Elapsed += Timer_Elapsed;
                    kvp.WindowsTimer.Timer.Enabled = true;
                }
               
            }
    
            private void Timer_Elapsed(object sender, ElapsedEventArgs e)
            {
                try
                {
                    #region 获取Command对象
    
                    WindowsServiceItem wsItem = _fTimerServices.GetItemByTimer((Timer)sender);
                    Type commandType = wsItem.CommandType;
                    ICommand command = null;
                    if (!_fTimerServiceObjects.ContainsKey(commandType))
                    {
                        lock (_fTimerServiceObjectsLock)
                        {
                            if (!_fTimerServiceObjects.ContainsKey(commandType))
                            {
                                var cmd = Activator.CreateInstance(commandType) as ICommand;
                                _fTimerServiceObjects.Add(commandType, cmd);
                                command = cmd;
                            }
                        }
                    }
                    else
                    {
                        command = _fTimerServiceObjects[commandType];
                    }
    
                    #endregion
    
                    if (!wsItem.WindowsTimer.Prepared)
                    {
                        return;
                    }
    
                    if (command != null)
                    {
                        lock (wsItem.WindowsTimer)
                        {
                            try
                            {
                                wsItem.WindowsTimer.Prepared = !wsItem.WindowsTimer.Prepared;
                                command.Execute();
                            }
                            catch (Exception ex)
                            {
                                //这里不应该导致整个服务终止,而只是把这个错误信号传递到外面去。
                                if (wsItem.WindowsTimer.CallBack != null)
                                {
                                    var args = new WindowsServiceTimerExceptionArgs(ex, e);
                                    try
                                    {
                                        wsItem.WindowsTimer.CallBack(wsItem.WindowsTimer, args);
                                    }
                                    catch (Exception ex1)
                                    {
                                        LogHelper.WriteErrorLog(ex1.ToString());           
                                    }
                                }
                            }
                            finally
                            {
                                wsItem.WindowsTimer.Prepared = !wsItem.WindowsTimer.Prepared;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.WriteErrorLog(ex.ToString());
                }
            }
    
           
    
            /// <summary>
            /// 服务停止执行的操作
            /// </summary>
            protected override void OnStop()
            {
                try
                {
                    foreach (WindowsServiceItem kvp in _fTimerServices)
                    {
                        kvp.WindowsTimer.Timer.Enabled = false;
                        try
                        {
                            kvp.WindowsTimer.Timer.Dispose();
                        }
                        catch (Exception ex)
                        {
                            LogHelper.WriteErrorLog(ex.ToString());
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.WriteErrorLog(ex.ToString());
                }
            }
    
            /// <summary>
            /// 释放Timer资源
            /// </summary>
            /// <param name="disposing"></param>
            protected override void Dispose(bool disposing)
            {
                if (disposing)
                {
                    if (_fTimerServices != null)
                    {
                        var timers = new List<WindowsTimer>();
                        foreach (WindowsServiceItem wt in _fTimerServices)
                        {
                            timers.Add(wt.WindowsTimer);
                        }
    
                        _fTimerServices.Clear();
                        foreach (WindowsTimer wt in timers)
                        {
                            wt.Dispose();
                        }
                    }
                }
                base.Dispose(disposing);
            }
        }

    五、服务demo

            开始服务demo的时候,这里我们这里稍微介绍服务帮助类WindowsServiceHelper.cs主要用于执行服务和异常的管理

    /// <summary>
        /// Windows服务辅助类
        /// </summary>
        [Serializable]
        public class WindowsServiceHelper
        {
            /// <summary>
            /// 
            /// </summary>
            static WindowsServiceHelper()
            {
                
            }
    
            /// <summary>
            /// 执行Windows服务
            /// </summary>
            public static void RunServices(WindowsServiceItemCollection timerServices, WindowsServiceTimerExceptionCallBack callBack)
            {
                WindowsServiceItemCollection.IsWindowsServiceEnviroments = true;
    
                try
                {
                    if (timerServices == null)
                    {
                        throw new ArgumentNullException("timerServices");
                    }
    
                    if (callBack != null)
                    {
                        foreach (WindowsServiceItem kvp in timerServices)
                        {
                            kvp.WindowsTimer.CallBack += callBack;
                        }
                    }
    
                    var servicesToRun = new ServiceBase[]
                    { 
                        new WindowsService(timerServices)            
                    };
    
                    foreach (ServiceBase service in servicesToRun)
                    {
                        service.AutoLog = true;
                    }
    
                    AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
    
                    ServiceBase.Run(servicesToRun);
                }
                catch (Exception ex)
                {
                    LogHelper.WriteErrorLog(ex.ToString());                  
                    throw;
                }
            }
    
            /// <summary>
            /// 未处理异常的处理
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
            {
                try
                {
                    if (e != null)
                    {
                        if (e.ExceptionObject != null)
                        {
                            if (e.ExceptionObject is Exception)
                            {
                                LogHelper.WriteErrorLog(e.ExceptionObject.ToString());
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.WriteErrorLog(ex.ToString());           
                }
            }
        }
    View Code

    接下来我们创建一个简单的Demo

    重新创建一个控制台程序,创建一个SendSmsCommand.cs 用于发信息,再创建一个SysDataToDataBase.cs用于同步数据到数据库。

      

     public class SendSmsCommand:ICommand
        {
            public void Execute()
            {
                // 服务的业务逻辑核心代码
                DoSomething();
            }
        }
     public class SysDataToDataBase:ICommand
        {
            public void Execute()
            {
                // 服务的业务逻辑核心代码
                DoSomething();
            }
        }    

    接下来就是将业务相关的服务进行注册,打开Program.cs修改main函数的代码如下:

     1 static void Main(string[] args)
     2         {
     3             try
     4             {
     5                 AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
     6                 var timerServices = new WindowsServiceItemCollection();
     7 
     8                 RegisterSendSmsService(timerServices);
     9                 RegisterSynDateService(timerServices);
    10                 WindowsServiceHelper.RunServices(timerServices, WindowsServiceTimerExceptionCallBack);
    11              
    12             }
    13             catch(Exception ex)
    14             {
    15                 WriterLog(ex.ToString(), "error");
    16             }
    17 
    18         }
    View Code

    RegisterSendSmsService方法就是用来注册发送信息服务,RegisterSynDateService用来注册同步数据服务。相关实现如下:

     private static void RegisterSynDateService(WindowsServiceItemCollection timerServices)
            {
                try
                {
                    const double interval = 1000;
                    var sendTimer = new WindowsTimer("SendSynDataInterval", interval);
                    timerServices.Add(sendTimer, typeof(SysDataToDataBase));
                }
                catch (Exception ex)
                {
                    Console.Write(ex);
                    WriterLog(ex.ToString(), "error");
                }
            }
    
            static void RegisterSendSmsService(WindowsServiceItemCollection timerServices)
            {
                #region 发送短信服务
                try
                {
                    const double interval = 1000;
                    var sendTimer = new WindowsTimer("SendSMSInterval", interval);
                    timerServices.Add(sendTimer, typeof(SendSmsCommand));
                }
                catch (Exception ex)
                {
                    Console.Write(ex);
                    WriterLog(ex.ToString(), "error");
                }
                #endregion
            }

    六、写在最后

           本快速搭建windows服务解决方案,主要好处就接口开发容易搭建多任务服务。服务框架也业务逻辑分离。把核心代码抽取到底层类库或者底层框架中,为团队其他成员创建服务带来便捷,他们不需要关心服务的如何具体实现的,只专注业务逻辑开发。

    本人很少写博客,也很少写总结相关文档,这次算是第一次写博客,语言和条理上自己感觉也比较混乱,自认为自己还是在学习阶段,需要想园区很多同仁学习,如果存在问题或者不理解地方欢迎大家文明讨论。再次谢谢大家。

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-1 05:54 , Processed in 0.069625 second(s), 30 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表