Community Server专题七: Job & Timer

Community Server专题七: Job & Timer
在CSHttpModule.cs文件中的Init方法下有这样一行:
接着在Dispose方法中还有这么一行:
Job?什么是Job,在CS运行过程中有什么用途,又是如何运行的?这篇专题将叙述Job的工作流程.
你可以这里理解CS中的Job:“干一些零碎事情的钟点工”。
讲解之前要先了解一个接口:IDisposable,MSDN是这样定义的:定义一种释放分配的非托管资源的方法。当托管对象不再使用时,垃圾回收器会自动释放分配给该对象的内存,不过,进行垃圾回收的时间不可预知。另外,垃圾回收器对窗口句柄、打开的文件和流等非托管资源一无所知。
将此接口的 Dispose 方法与垃圾回收器一起使用来显式释放非托管资源。当不再需要对象时,对象的使用者可以调用此方法。非托管资源(unmanaged resource)?大致可以这样理解:类实例封装的对不受运行库管理的资源(窗口句柄、数据库连接等),这些类实例都必须实现IDisposable接口,如:SqlCommand 、SqlCeConnection、Timer等。当一个类实现IDisposable时,实例的正确用法是当对象不在需要时调用Dispose方法删除它,因此,在你实现一个类,而该类又包含其他实现IDisposable的类时,必须调用Dispose方法。这通常意味着在该类中你必须实现IDisposable。
注:C#语言对Disposable有特殊的支持,你经常会看到如下一段代码:

using(SqlConnection connection = new SqlConnection(connectionString))

{

    //
do something

}

这里的using就是对IDisposable接口的支持来实现对象清除。
言归正传,下面打开CommunityServerComponents项目中Configuration文件夹中的Job.cs:

public class Job : IDisposable

{

//代码太长…

}

原来Job是实现了IDisposable的类,有了上面对IDisposable的解释不难理解,由于Job中调用了Timer,而Timer又是实现了IDisposable的类,Job类实现接口IDisposable是为了释放使用的Timer,即调用Timer中的Dispose()。看看以下的代码可以证实这一点:

public void Dispose()

{

    
if(_timer!= null && !disposed)

    
{

        
lock(this)

        
{

            _timer.Dispose();

            _timer 
= null;

            disposed 
= true;

        }


    }


}

还有必要对Timer类做一些简单的介绍:Timer是提供以指定的时间间隔执行方法的机制,说白了就是一个定时器。Timer可以使用 TimerCallback 委托指定希望 Timer时间到达时执行的方法。也就是说,如果定时器的时间到达了,将执行TimerCallback 委托指向的方法。
(注:创建计时器时,可以指定在第一次执行方法之前等待的时间量(截止时间)以及此后的执行期间等待的时间量(时间周期)。可以使用 Change 方法更改这些值或禁用计时器。)
我们看一下代码:

_timer = new Timer(new TimerCallback(timer_Callback), id,Interval, Interval);

private Timer _timer = null;

public void InitializeTimer(Guid id)

{

     
if(_timer == null && Enabled)

     
{

         _timer 
= new Timer(new TimerCallback(timer_Callback), id,Interval, Interval);

     }


}


 

private void timer_Callback(object state)

{

    Guid id 
= (Guid)state;

    
if(id != Jobs.Instance().CurrentID)

    
{

        
this.Dispose();

        
return;

    }


 

 

 

    
if(!Enabled)

        
return;

 

    _timer.Change( Timeout.Infinite, Timeout.Infinite );

 

    ExecuteJob();

 

    
if(Enabled)

        _timer.Change( Interval, Interval);

    
else

        
this.Dispose();

 

}

通过
先实例化了一个定时器,并制定了该定时器触发时候调用的方法是timer_Callback。
(前一个Interval指:
后一个Interval指:
)
在回调方法timer_Callback只要调用的是ExecuteJob()方法,该方法通过调用Job类的Jobs类中传递过来得xml节点信息,使用反射实例化一个具有IJob接口的类(IJob接口要求实现它的类都具有Execute方法),并且执行类中的Execute方法。我们分析一个实现了IJob的类,打开Components文件夹下的EmailJob.cs,该类中只有一个方法,就是Execute,该方法又调用Emails.cs下的SendQueuedEmails方法,主要用途是发送数据库队列中的Email(这里Email来源于用户注册时需要发送的注册成功的信息等等,通常的做法是在用户注册完毕后马上就发送Email,而CS采用的是将要发送的Email存入数据库,在一定的间隔时间后统一处理这段时间内的所有Email发送,处理的类就是EmailJob.cs)。这里还要注意一点:TimerCallback的实例不在创建计时器的线程中执行,而是在系统提供的一个单独线程池线程中执行。
再来看看CommunityServerComponents项目下的Jobs.cs文件,这个类第一次看设计的有点蹩脚,它的构造函数是静态的,但是在静态的构造函数中实例化它自己,实例化后保存在static readonly的变量里(晕了吧,嘿嘿!)其实这叫单件模式(Singleton模式),确保全局中有且只有一个Jobs实例。Jobs的实例主要完成从CS的配置文件中读取出每个Job的配置信息,先看一下Job的配置信息:
<Jobs minutes = "5" singleThread = "false">

         
<job name = "SiteStatisticsUpdates" type = "CommunityServer.Components.SiteStatisticsJob, CommunityServer.Components" enabled = "true" enableShutDown = "false" />

         
<job name = "ForumsIndexing" type = "CommunityServer.Discussions.Components.ForumsSearchJob, CommunityServer.Discussions" enabled = "false" enableShutDown = "false" />

         
<job name = "WeblogIndexing" type = "CommunityServer.Blogs.Components.WeblogSearchJob, CommunityServer.Blogs" enabled = "false" enableShutDown = "false" />

         
<job name = "GalleryIndexing" type = "CommunityServer.Galleries.Components.GallerySearchJob, CommunityServer.Galleries" enabled = "false" enableShutDown = "false" />

         

         
<job name = "AnonymousUsers" minutes = "1" type = "CommunityServer.Components.AnonymousUserJob, CommunityServer.Components" enabled = "true" enableShutDown = "false" />

         
<job singleThread = "false" minutes = "5" name = "Emails" type = "CommunityServer.Components.EmailJob, CommunityServer.Components" enabled = "true" enableShutDown = "false" failureInterval = "1" numberOfTries = "10" />

         
<job name = "Referrals" type = "CommunityServer.Components.ReferralsJob, CommunityServer.Components" enabled = "true" enableShutDown = "false" />

         
<job name = "Views" type = "CommunityServer.Components.ViewsJob, CommunityServer.Components" enabled = "true" enableShutDown = "false" />

         
<job name = "RecentBlogContent" type = "CommunityServer.Blogs.Components.RecentContentJob, CommunityServer.Blogs" enabled = "true" enableShutDown = "false" />

         
<job name = "RebuildThumbnailsJob" type = "CommunityServer.Galleries.Components.RebuildThumbnailsJob, CommunityServer.Galleries" picturesPerRun = "25" enabled = "true" enableShutDown = "false" />

</Jobs>

解释一下这些xml的节点意思:
  
<Jobs minutes = "5" singleThread = "false">
minutes:执行回调函数TimerCallback的时间与时间间隔,这里是5分钟,也就是说执行回调函数在初始化请求之后的五分钟开始,并且每五分钟一次。
singleThread:是单线程还是多线程,前面说过为Timer创建的TimerCallback的实例不在创建计时器的线程中执行,而是在系统提供的一个单独线程池线程中执行,如果值为“false”就会为每个Job创建一个Timer线程,如果为“true”就创建一个Timer。
<job>节点比较灵活,一些属性是该节点特有的,这是根据实现IJob接口类的需要决定的,以Email发送的类为例:
:当头CS版本中没有用到。
<job singleThread = "false" minutes = "5" name = "Emails" type = "CommunityServer.Components.EmailJob, CommunityServer.Components" enabled = "true" enableShutDown = "false" failureInterval = "1" numberOfTries = "10" />

singleThread
Minutes:执行回调函数TimerCallback的时间与时间间隔,这里是5分钟。
name:该Job的唯一标识。
type:该Job所在的名字空间,逗号后面的是该Job所在的程序集dll文件名称。
enabled:如果为“false”该Job会被关闭,也就是不会实例化一个定时器。“true”则为开启该Job。
enableShutDown:这个有点意思,用途是当该Job在执行Execute时,如果长生异常是否关闭这个Job,也就是说是否还允许它再次运行。“false”表示允许,“true”表示不允许。
failureInterval:如果发送邮件失败,与下次尝试再次发送的时间间隔,单位是分钟。
numberOfTries:如果发送邮件失败,该Job会尝试几次,这里是10次。
   现在回到我们开始时候在CSHttpModule.cs中看到的这句:
Jobs.Instance().Start();
首先调用Jobs,实例化一个Jobs类,这个类在CS中有且只有一个实例。之后调用Jobs中的Start()方法。Jobs为了确保系统的安全,在开始之前先调用Stop(),现释放之前为Job实例化的非托管资源(其实就是调用Timer与Job下面的Dispose方法,这也是为什么Job要实现IDispose接口的原因,是想一下,如果前一次定义的定时器没有被释放,然后又接着实例化一个,然后这样多重复几次...哈哈,你的CS就会有N个线程在跑,服务器很快就会挂掉的)。
释放完资源后(无论有没有CS都会这么做),接着就会实例化每个实现了IJob的类,根据上述的配置文件定义一个Timer或者让每个Job都定义一个自己的Timer(这就相当于给钟点工统一一个工作时间或者给每个钟点工都规定一个工作时间,规定完后该干什么的就干去吧,只要时间到了就得干活)。再往下,就自己分析吧,也就没有什么难题了…
 
不知道为什么我的团队中的几个成员老是不能理解这个执行过程,我解释了半天,最后发现了问题:
回到CSHttpModule.cs文件中来,这是一个实现了IHttpModule接口的类,实现该接口的类都要有一个Init方法,我们看到,所有的Job开始初始化的起点也是从这个方法中调用的。但是我的小组成员都认为每个Http请求都会调用一次Init方法,
public void Init(HttpApplication application) 



    // Wire-up application events

    //

    application.BeginRequest += new EventHandler(this.Application_BeginRequest);

    application.AuthenticateRequest += new EventHandler(Application_AuthenticateRequest);

    application.Error += new EventHandler(this.Application_OnError);

    application.AuthorizeRequest += new EventHandler(this.Application_AuthorizeRequest);

    

    //settingsID = SiteSettingsManager.GetSiteSettings(application.Context).SettingsID;

    Jobs.Instance().Start();

    //CSException ex = new CSException(CSExceptionType.ApplicationStart, "Appication Started " +  AppDomain.CurrentDomain.FriendlyName);

    //ex.Log();

}

也就是说每个请求都实例化一个CSHttpModule,如果是这样Init方法就会多次被调用,那么如果有1000个Http请求Jobs就会Start 1000次,这本来就分析不通。
其实认为CSHttpModule会被实例化多次就是一个很大的错误,在整个CS运行过程中只会实例化一个CSHttpModule类,也就是说Init只会被执行一次。
 
 

Trackback: http://tb.blog.youkuaiyun.com/TrackBack.aspx?PostId=1538954

 
【基于QT的调色板】是一个使用Qt框架开发的色彩选择工具,类似于Windows操作系统中常见的颜色选取器。Qt是一个跨平台的应用程序开发框架,广泛应用于桌面、移动和嵌入式设备,支持C++和QML语言。这个调色板功能提供了横竖两种渐变模式,用户可以方便地选取所需的颜色值。 在Qt中,调色板(QPalette)是一个关键的类,用于管理应用程序的视觉样式。QPalette包含了一系列的颜色角色,如背景色、前景色、文本色、高亮色等,这些颜色可以根据用户的系统设置或应用程序的需求进行定制。通过自定义QPalette,开发者可以创建具有独特视觉风格的应用程序。 该调色板功能可能使用了QColorDialog,这是一个标准的Qt对话框,允许用户选择颜色。QColorDialog提供了一种简单的方式来获取用户的颜色选择,通常包括一个调色板界面,用户可以通过滑动或点击来选择RGB、HSV或其他色彩模型中的颜色。 横渐变取色可能通过QGradient实现,QGradient允许开发者创建线性或径向的色彩渐变。线性渐变(QLinearGradient)沿直线从一个点到另一个点过渡颜色,而径向渐变(QRadialGradient)则以圆心为中心向外扩散颜色。在调色板中,用户可能可以通过滑动条或鼠标拖动来改变渐变的位置,从而选取不同位置的颜色。 竖渐变取色则可能是通过调整QGradient的方向来实现的,将原本水平的渐变方向改为垂直。这种设计可以提供另一种方式来探索颜色空间,使得选取颜色更为直观和便捷。 在【colorpanelhsb】这个文件名中,我们可以推测这是与HSB(色相、饱和度、亮度)色彩模型相关的代码或资源。HSB模型是另一种常见且直观的颜色表示方式,与RGB或CMYK模型不同,它以人的感知为基础,更容易理解。在这个调色板中,用户可能可以通过调整H、S、B三个参数来选取所需的颜色。 基于QT的调色板是一个利用Qt框架和其提供的色彩管理工具,如QPalette、QColorDialog、QGradient等,构建的交互式颜色选择组件。它不仅提供了横竖渐变的色彩选取方式,还可能支持HSB色彩模型,使得用户在开发图形用户界面时能更加灵活和精准地控制色彩。
标题基于Spring Boot的二手物品交易网站系统研究AI更换标题第1章引言阐述基于Spring Boot开发二手物品交易网站的研究背景、意义、现状及本文方法与创新点。1.1研究背景与意义介绍二手物品交易的市场需求和Spring Boot技术的适用性。1.2国内外研究现状概述当前二手物品交易网站的发展现状和趋势。1.3论文方法与创新点说明本文采用的研究方法和在系统设计中的创新之处。第2章相关理论与技术介绍开发二手物品交易网站所涉及的相关理论和关键技术。2.1Spring Boot框架解释Spring Boot的核心概念和主要特性。2.2数据库技术讨论适用的数据库技术及其在系统中的角色。2.3前端技术阐述与后端配合的前端技术及其在系统中的应用。第3章系统需求分析详细分析二手物品交易网站系统的功能需求和性能需求。3.1功能需求列举系统应实现的主要功能模块。3.2性能需求明确系统应满足的性能指标和安全性要求。第4章系统设计与实现具体描述基于Spring Boot的二手物品交易网站系统的设计和实现过程。4.1系统架构设计给出系统的整体架构设计和各模块间的交互方式。4.2数据库设计详细阐述数据库的结构设计和数据操作流程。4.3界面设计与实现介绍系统的界面设计和用户交互的实现细节。第5章系统测试与优化说明对系统进行测试的方法和性能优化的措施。5.1测试方法与步骤测试环境的搭建、测试数据的准备及测试流程。5.2测试结果分析对测试结果进行详细分析,验证系统是否满足需求。5.3性能优化措施提出针对系统性能瓶颈的优化建议和实施方案。第6章结论与展望总结研究成果,并展望未来可能的研究方向和改进空间。6.1研究结论概括本文基于Spring Boot开发二手物品交易网站的主要发现和成果。6.2展望与改进讨论未来可能的系统改进方向和新的功能拓展。
1. 用户与权限管理模块 角色管理: 学生:查看个人住宿信息、提交报修申请、查看卫生检查结果、请假外出登记 宿管人员:分配宿舍床位、处理报修申请、记录卫生检查结果、登记晚归情况 管理员:维护楼栋与房间信息、管理用户账号、统计住宿数据、发布宿舍通知 用户操作: 登录认证:对接学校统一身份认证(模拟实现,用学号 / 工号作为账号),支持密码重置 信息管理:学生完善个人信息(院系、专业、联系电话),管理员维护所有用户信息 权限控制:不同角色仅可见对应功能(如学生无法修改床位分配信息) 2. 宿舍信息管理模块 楼栋与房间管理: 楼栋信息:名称(如 &quot;1 号宿舍楼&quot;)、层数、性别限制(男 / 女 / 混合)、管理员(宿管) 房间信息:房间号(如 &quot;101&quot;)、户型(4 人间 / 6 人间)、床位数量、已住人数、可用状态 设施信息:记录房间内设施(如空调、热水器、桌椅)的配置与完好状态 床位管理: 床位编号:为每个床位设置唯一编号(如 &quot;101-1&quot; 表示 101 房间 1 号床) 状态标记:标记床位为 &quot;空闲 / 已分配 / 维修中&quot;,支持批量查询空闲床位 历史记录:保存床位的分配变更记录(如从学生 A 调换到学生 B 的时间与原因) 3. 住宿分配与调整模块 住宿分配: 新生分配:管理员导入新生名单后,宿管可按专业集中、性别匹配等规则批量分配床位 手动分配:针对转专业、复学学生,宿管手动指定空闲床位并记录分配时间 分配结果公示:学生登录后可查看自己的宿舍信息(楼栋、房间号、床位号、室友列表) 调整管理: 调宿申请:学生提交调宿原因(如室友矛盾、身体原因),选择意向宿舍(需有空位) 审批流程:宿管审核申请,通过后执行床位调换,更新双方住宿信息 换宿记录:保存调宿历史(申请人、原床位、新床位、审批人、时间) 4. 报修与安全管理模块 报修管理: 报修提交:学生选择宿舍、设施类型(如 &quot;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值