1.简单介绍
XAgent为大石头带领下的新生命团队自己开发的一个.Net下的常用的Windows服务管理组件利器,通过在控制台中简单的输入1,2,3,4,5等数字可以实现一步安装、卸载WindowsService以及单步调试和循环调试、服务停止,重启、运行,用起来很方便。看效果(具体使用方法可以去XAgent官网查看):
2.当前使用场景介绍及实现
我的这个项目下面有很多控制台应用程序需要运行,平时部署很麻烦,不方便管理。我的想法是把这些程序以插件的形式放到一个应用程序中运行管理。这里写了一个Ijob接口。看代码:
Ijob相关代码
/// <summary>工作接口</summary>
public interface IJob
{
/// <summary>
/// 工作组件顺序
/// </summary>
int Sort { get; set; }
/// <summary>
/// 间隔时间
/// </summary>
int JobInterval { get; set; }
/// <summary>启动</summary>
/// <returns></returns>
bool Start();
/// <summary>停止</summary>
/// <returns></returns>
bool Stop();
/// <summary>工作</summary>
bool Work();
//void WriteLog(string format, params object[] args);
}
/// <summary>基础工作组件</summary>
public class Job : IJob
{
///// <summary>
///// 是否执行
///// </summary>
//public bool IsExcute { get; set; }
public Job()
{
Sort = 0;
DisplayName = "基础工作组件";
JobInterval = 60; //默认60秒
//IsExcute = true;//默认执行
}
/// <summary>工作组件名</summary>
public virtual string DisplayName { get; set; }
/// <summary>工作组件顺序</summary>
public virtual int Sort { get; set; }
/// <summary>
/// 时间间隔
/// </summary>
public int JobInterval { get; set; }
/// <summary>启动</summary>
public virtual bool Start()
{
WriteLog("开始工作");
return false;
}
/// <summary>停止</summary>
/// <returns></returns>
public virtual bool Stop()
{
WriteLog("停止工作");
return false;
}
/// <summary>工作</summary>
public virtual bool Work()
{
WriteLog("正在运行");
return false;
}
public virtual void WriteLog(string format, params object[] args)
{
//XTrace.WriteLine("[" + this.GetType() + "] [" + DisplayName + "] " + format, args);
XTrace.WriteLine("[" + DisplayName + "] " + format, args);
}
View Code
public static class JobHelper
{
static readonly List<Type> _hasInited = new List<Type>();
private static List<IJob> op_cache = new List<IJob>();
/// <summary>所有工作组件</summary>
public static List<IJob> Works
{
get
{
var list = LoadWork();
foreach (var item in list)
{
EnsureInit(item);
}
op_cache = op_cache.OrderBy(j => j.Sort).ToList();
return op_cache;
}
}
/// <summary>确保实体类已经执行完静态构造函数,因为那里实在是太容易导致死锁了</summary>
/// <param name="type">类型</param>
internal static void EnsureInit(Type type)
{
if (_hasInited.Contains(type)) return;
// 先实例化,在锁里面添加到列表但不实例化,避免实体类的实例化过程中访问CreateOperate导致死锁产生
var item = type.CreateInstance();
lock (_hasInited)
// 如果这里锁定_hasInited,还是有可能死锁,因为可能实体类A的静态构造函数中可能导致调用另一个实体类的EnsureInit
// 其实我们这里加锁的目的,本来就是为了避免重复添加同一个type而已
//lock ("_hasInited" + type.FullName)
{
if (_hasInited.Contains(type)) return;
if (op_cache.Contains(item as IJob)) return;
op_cache.Add(item as IJob);
//type.CreateInstance();
_hasInited.Add(type);
}
}
/// <summary>列出所有工作接口</summary>
/// <returns></returns>
public static List<Type> LoadWork()
{
return typeof (IJob).GetAllSubclasses(true).ToList();
}
}
View Code 确保所有的工作组件继承Job类,重写其中的方法,将一些需要配置的属性做成xml进行管理。废话不说看代码:
这是其中一个工作插件
public HourStatisticsWork()
{
DisplayName = "小时统计组件";
Sort = 2;
if (WorkSetting.Current.HourStatisticsEnable)
{
JobInterval = WorkSetting.Current.HourStatisticsInterval;
}
else
{
JobInterval = -1; //禁用此组件
}
}
public override bool Work()
{
StartWork();
return base.Work();
}
public override bool Stop()
{
if (_HourTimer != null)
{
_HourTimer.Dispose();
}
return base.Stop();
}
public void StartWork()
{
try
{
// Console.WriteLine("当前时间{0}",DateTime.Now);
//var time = WorkSetting.Current.HourStatisticsInterval;
//// 定时器一分钟后启动
//if (_HourTimer == null)
// _HourTimer = new TimerX(obj =>
// {
// StartWork();
// }, null, 3 * 1000, time);
DateTime dt = DateTime.Now.AddHours(-1);
cyStatistics(dt);
sccStatistics(dt);
ccStatistics(dt);
jcStatistics(dt);
mfStatistics(dt);
vcStatistics(dt);
vbStatistics(dt);
pulStatistics(dt);
icStatistics(dt);
rhcStatistics(dt);
dtrStatistics(dt);
MotorLoadStatistics(dt);
TimeStatistics(dt);
Container.Info("[HourStatisticsWork]Hour Statistics");
}
catch (Exception ex)
{
Container.Error($"[HourStatisticsWork]{ex.Message}");
}
}
View Code 相关配置项
[DisplayName("运行参数设置")]
[XmlConfigFile(@"Config\WorkSetting.config", 15000)]
public class WorkSetting : XmlConfig<WorkSetting>
{
//private String _LastTool;
///// <summary>最后一个使用的工具</summary>
//[DisplayName("最后一个使用的工具")]
//public String LastTool { get { return _LastTool; } set { _LastTool = value; } }
protected override void OnNew()
{
SystemName = "物联网监控系统";
LastUpdateTime = new DateTime(2017, 1, 1);
RabbitMqResolveEnable = true;
RabbitMqResolveInterval = 1;//默认1s
HourStatisticsEnable = true;
HourStatisticsInterval = 30*60;//默认30min
DayStatisticsEnable = true;
DayStatisticsInterval = 12 * 60*60;//默认12个小时
EnableViewServiceLog = false;
}
#region 队列解析
[Description("启用队列解析")]
public bool RabbitMqResolveEnable { get; set; }
[Description("队列解析间隔时间,单位:秒")]
public int RabbitMqResolveInterval { get; set; }
#endregion
#region 小时统计
[Description("启用小时统计")]
public bool HourStatisticsEnable { get; set; }
[Description("小时统计间隔时间,单位:秒")]
public int HourStatisticsInterval { get; set; }
#endregion
#region 自然日统计
[Description("启用自然日统计")]
public bool DayStatisticsEnable { get; set; }
[Description("自然日统计间隔时间,单位:秒")]
public int DayStatisticsInterval { get; set; }
#endregion
#region 异常通知
[Description("启用异常通知")]
public bool ExceptionNotifyEnable { get; set; }
[Description("异常通知级别")]
public int ExceptionNotifyLevel { get; set; }
#endregion 异常通知
#region 系统
/// <summary>
/// 系统名称
/// </summary>
[Description("系统名称")]
public String SystemName { get; set; }
/// <summary>最后更新时间</summary>
[Description("最后更新时间")]
public DateTime LastUpdateTime { get; set; }
#endregion 系统
#region Windows Service
/// <summary>服务名</summary>
[Description("服务名")]
public String ServiceName { get; set; }
/// <summary>显示名</summary>
[Description("显示名")]
public String DisplayName { get; set; }
/// <summary>服务描述</summary>
[Description("服务描述")]
public String Description { get; set; }
/// <summary>查看服务运行日志</summary>
[Description("查看服务运行日志")]
public bool EnableViewServiceLog { get; set; }
#endregion Windows Service
}
View Code 一切准备好后,开始生成项目并运行,效果如下:
3.发现问题
看起来一切运行正常,但是等到我讲xml文件中的HourStatisticsEnable设置成false时,发现只有第一个队列解析的服务在运行。第三个自然日统计的服务没有运行。这时我注意到,原来是插件运行的先后顺序影响的,即Sort属性。本质上还是JobInterval控制了改插件是否运行。可能XAgent的源代码有些小问题,我没有继续深入到源代码中去查找解决,而是直接通过xml配置文件的Enable判断该组件是否运行。
代码如下:
public HourStatisticsWork()
{
if (WorkSetting.Current.HourStatisticsEnable)
{
DisplayName = "小时统计组件";
Sort = 2;
JobInterval = WorkSetting.Current.HourStatisticsInterval;
}
else
{
//JobInterval = -1; //禁用此组件
}
}
public override bool Work()
{
if (WorkSetting.Current.HourStatisticsEnable)
{
StartWork();
}
return base.Work();
}
public override bool Stop()
{
if (_HourTimer != null)
{
_HourTimer.Dispose();
}
return base.Stop();
}
public void StartWork()
{//todo}
View Code 另外,该IJob接口借鉴了我曾经的领导的想法。
供大家学习,如有不正不妥之处请大家指正。谢谢!
需要源码的或者帮助的联系我QQ:694666781
运维网声明
1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网 享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com