qurtz.net(转载)
Quartz+TopShelf实现Windows服务作业调度
Quartz:首先我贴出来了两段代码(下方),可以看出,首先会根据配置文件(quartz.config),包装出一个Quartz.Core.QuartzScheduler
instance,这是一个调度器,调度各个任务项(Jobs)的执行。这个调度器可以被Start、被Shutdown、被PauseAll、被ResumeAll,这对应
了windows服务的开启、停止、暂停、恢复。当启动服务,我就调用调度器的Start(),停止服务我就调用调度器的Shutdown()方法。

- namespace QTDemo
- {
- public class ServiceRunner : ServiceControl, ServiceSuspend
- {
- private readonly IScheduler scheduler;
- public ServiceRunner()
- {
- scheduler = StdSchedulerFactory.GetDefaultScheduler();
- }
- public bool Start(HostControl hostControl)
- {
- scheduler.Start();
- return true;
- }


- // 摘要:
- // An implementation of Quartz.ISchedulerFactory that does all of it's work
- // of creating a Quartz.Core.QuartzScheduler instance based on the contents
- // of a properties file.
- public class StdSchedulerFactory : ISchedulerFactory
- {
- public const string AutoGenerateInstanceId = "AUTO";
- public const string ConfigurationSectionName = "quartz";
- public const string DefaultInstanceId = "NON_CLUSTERED";
- public const string PropertiesFile = "quartz.config";

那TopShelf又扮演了什么样的角色呢
这是一个宿主服务的框架。和ServiceBase、ServiceInstaller那一套的目的一样,都是用来创建Windows服务的。
项目示例
1、新建项目控制台应用程序‘QTDemo’
2、从NuGet安装‘Quartz’,‘Topshelf’,‘Topshelf.Log4Net’

- 1 <?xml version="1.0" encoding="utf-8"?>
- 2 <packages>
- 3 <package id="Common.Logging" version="3.3.1" targetFramework="net45" />
- 4 <package id="Common.Logging.Core" version="3.3.1" targetFramework="net45" />
- 5 <package id="log4net" version="2.0.5" targetFramework="net45" />
- 6 <package id="Quartz" version="2.3.3" targetFramework="net45" />
- 7 <package id="Topshelf" version="3.3.1" targetFramework="net45" />
- 8 <package id="Topshelf.Log4Net" version="3.3.1" targetFramework="net45" />
- 9 </packages>

3、定义一个Job(一个任务项),继承Quartz.IJob

- 1 using Quartz;
- 2 namespace QTDemo.QuartzJobs
- 3 {
- 4 public sealed class TestJob : IJob
- 5 {
- 6 public void Execute(IJobExecutionContext context)
- 7 {
- 8 CommonHelper.AppLogger.InfoFormat("TestJob测试");
- 9
- 10 }
- 11 }
- 12 }
- 13

4、配置(新建)quartz.config、quartz_jobs.xml
quartz.config可直接使用,不用修改

- 1 # You can configure your scheduler in either <quartz> configuration section
- 2 # or in quartz properties file
- 3 # Configuration section has precedence
- 4
- 5 quartz.scheduler.instanceName = QuartzTest
- 6
- 7 # configure thread pool info
- 8 quartz.threadPool.type = Quartz.Simpl.SimpleThreadPool, Quartz
- 9 quartz.threadPool.threadCount = 10
- 10 quartz.threadPool.threadPriority = Normal
- 11
- 12 # job initialization plugin handles our xml reading, without it defaults are used
- 13 quartz.plugin.xml.type = Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz
- 14 quartz.plugin.xml.fileNames = ~/quartz_jobs.xml
- 15
- 16 # export this server to remoting context
- 17 #quartz.scheduler.exporter.type = Quartz.Simpl.RemotingSchedulerExporter, Quartz
- 18 #quartz.scheduler.exporter.port = 555
- 19 #quartz.scheduler.exporter.bindName = QuartzScheduler
- 20 #quartz.scheduler.exporter.channelType = tcp
- 21 #quartz.scheduler.exporter.channelName = httpQuartz

quartz_jobs.xml根据实际的Job项修改

- 1 <?xml version="1.0" encoding="utf-8" ?>
- 2 <!-- This file contains job definitions in schema version 2.0 format -->
- 3
- 4 <job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0">
- 5
- 6 <processing-directives>
- 7 <overwrite-existing-data>true</overwrite-existing-data>
- 8 </processing-directives>
- 9
- 10 <schedule>
- 11
- 12 <!--TestJob测试 任务配置 -->
- 13 <job>
- 14 <name>TestJob</name>
- 15 <group>Test</group>
- 16 <description>TestJob测试</description>
- 17 <job-type>QTDemo.QuartzJobs.TestJob,QTDemo</job-type>
- 18 <durable>true</durable>
- 19 <recover>false</recover>
- 20 </job>
- 21 <trigger>
- 22 <cron>
- 23 <name>TestJobTrigger</name>
- 24 <group>Test</group>
- 25 <job-name>TestJob</job-name>
- 26 <job-group>Test</job-group>
- 27 <!-- 从start-time起,每5s执行一次IJob.Execute -->
- 28 <start-time>2012-01-22T00:00:00+08:00</start-time>
- 29 <cron-expression>0/5 * * * * ?</cron-expression>
- 30 </cron>
- 31 </trigger>
- 32
- 33 </schedule>
- 34 </job-scheduling-data>

5、创建服务
入口:

- 1 using System;
- 2 using System.IO;
- 3 using Topshelf;
- 4
- 5 namespace QTDemo
- 6 {
- 7 class Program
- 8 {
- 9 static void Main(string[] args)
- 10 {
- 11 log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(AppDomain.CurrentDomain.BaseDirectory + "log4net.config"));
- 12
- 16 HostFactory.Run(x =>
- 17 {
- 18 x.UseLog4Net();
- 19
- 20 x.Service<ServiceRunner>();
- 21
- 22 x.RunAsLocalSystem();
- 23
- 24 x.SetDescription("Quartz+TopShelf实现Windows服务作业调度的一个示例Demo");
- 25 x.SetDisplayName("QuartzTopShelfDemo服务");
- 26 x.SetServiceName("QuartzTopShelfDemoService");
- 27
- 28 x.EnablePauseAndContinue();
- 29
- 30 });
- 31 }
- 32 }
- 33 }

ServiceRunner.cs

- 1 using Quartz;
- 2 using Quartz.Impl;
- 3 using Topshelf;
- 4
- 5 namespace QTDemo
- 6 {
- 7 public class ServiceRunner : ServiceControl, ServiceSuspend
- 8 {
- 9 private readonly IScheduler scheduler;
- 10
- 11 public ServiceRunner()
- 12 {
- 13 scheduler = StdSchedulerFactory.GetDefaultScheduler();
- 14 }
- 15
- 16 public bool Start(HostControl hostControl)
- 17 {
- 18 scheduler.Start();
- 19 return true;
- 20 }
- 21
- 22 public bool Stop(HostControl hostControl)
- 23 {
- 24 scheduler.Shutdown(false);
- 25 return true;
- 26 }
- 27
- 28 public bool Continue(HostControl hostControl)
- 29 {
- 30 scheduler.ResumeAll();
- 31 return true;
- 32 }
- 33
- 34 public bool Pause(HostControl hostControl)
- 35 {
- 36 scheduler.PauseAll();
- 37 return true;
- 38 }
- 39
- 40 }
- 41 }

log4net配置文件,可直接使用
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<log4net>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<!--日志路径-->
<param name= "File" value= "Log\"/>
<!--是否是向文件中追加日志-->
<param name= "AppendToFile" value= "true"/>
<!--log保留天数-->
<param name= "MaxSizeRollBackups" value= "10"/>
<!--日志文件名是否是固定不变的-->
<param name= "StaticLogFileName" value= "false"/>
<!--日志文件名格式为:2008-08-31.log-->
<param name= "DatePattern" value= "yyyy-MM-dd".read.log""/>
<!--日志根据日期滚动-->
<param name= "RollingStyle" value= "Date"/>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%date{HH:mm:ss,fff} %-5p-%m%n" />
</layout>
</appender>
<!-- 控制台前台显示日志 -->
<appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
<mapping>
<level value="ERROR" />
<foreColor value="Red, HighIntensity" />
</mapping>
<mapping>
<level value="Info" />
<foreColor value="Green" />
</mapping>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%n%date{HH:mm:ss,fff} [%-5level] %m" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="Info" />
<param name="LevelMax" value="Fatal" />
</filter>
</appender>
<root>
<!--(高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (低) -->
<level value="all" />
<appender-ref ref="ColoredConsoleAppender"/>
<appender-ref ref="RollingLogFileAppender"/>
</root>
</log4net>
</configuration>

- 1 <?xml version="1.0" encoding="utf-8" ?>
- 2 <configuration>
- 3 <configSections>
- 4 <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
- 5 </configSections>
- 6
- 7 <log4net>
- 8 <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
- 9 <!--日志路径-->
- 10 <param name= "File" value= "Log\"/>
- 11 <!--是否是向文件中追加日志-->
- 12 <param name= "AppendToFile" value= "true"/>
- 13 <!--log保留天数-->
- 14 <param name= "MaxSizeRollBackups" value= "10"/>
- 15 <!--日志文件名是否是固定不变的-->
- 16 <param name= "StaticLogFileName" value= "false"/>
- 17 <!--日志文件名格式为:2008-08-31.log-->
- 18 <param name= "DatePattern" value= "yyyy-MM-dd".read.log""/>
- 19 <!--日志根据日期滚动-->
- 20 <param name= "RollingStyle" value= "Date"/>
- 21 <layout type="log4net.Layout.PatternLayout">
- 22 <param name="ConversionPattern" value="%date{HH:mm:ss,fff} %-5p-%m%n" />
- 23 </layout>
- 24 </appender>
- 25
- 26 <!-- 控制台前台显示日志 -->
- 27 <appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
- 28 <mapping>
- 29 <level value="ERROR" />
- 30 <foreColor value="Red, HighIntensity" />
- 31 </mapping>
- 32 <mapping>
- 33 <level value="Info" />
- 34 <foreColor value="Green" />
- 35 </mapping>
- 36 <layout type="log4net.Layout.PatternLayout">
- 37 <conversionPattern value="%n%date{HH:mm:ss,fff} [%-5level] %m" />
- 38 </layout>
- 39
- 40 <filter type="log4net.Filter.LevelRangeFilter">
- 41 <param name="LevelMin" value="Info" />
- 42 <param name="LevelMax" value="Fatal" />
- 43 </filter>
- 44 </appender>
- 45
- 46 <root>
- 47 <!--(高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (低) -->
- 48 <level value="all" />
- 49 <appender-ref ref="ColoredConsoleAppender"/>
- 50 <appender-ref ref="RollingLogFileAppender"/>
- 51 </root>
- 52
- 53 </log4net>
- 54 </configuration>

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<log4net>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<!--日志路径-->
<param name= "File" value= "Log\"/>
<!--是否是向文件中追加日志-->
<param name= "AppendToFile" value= "true"/>
<!--log保留天数-->
<param name= "MaxSizeRollBackups" value= "10"/>
<!--日志文件名是否是固定不变的-->
<param name= "StaticLogFileName" value= "false"/>
<!--日志文件名格式为:2008-08-31.log-->
<param name= "DatePattern" value= "yyyy-MM-dd".read.log""/>
<!--日志根据日期滚动-->
<param name= "RollingStyle" value= "Date"/>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%date{HH:mm:ss,fff} %-5p-%m%n" />
</layout>
</appender>
<!-- 控制台前台显示日志 -->
<appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
<mapping>
<level value="ERROR" />
<foreColor value="Red, HighIntensity" />
</mapping>
<mapping>
<level value="Info" />
<foreColor value="Green" />
</mapping>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%n%date{HH:mm:ss,fff} [%-5level] %m" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="Info" />
<param name="LevelMax" value="Fatal" />
</filter>
</appender>
<root>
<!--(高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (低) -->
<level value="all" />
<appender-ref ref="ColoredConsoleAppender"/>
<appender-ref ref="RollingLogFileAppender"/>
</root>
</log4net>
</configuration>
6、quartz.config、quartz_jobs.xml、log4net.config都设置成‘始终复制’
7、直接F5,调试,发现TestJob每5s执行一次
8、安装成Windows服务
用Release编一个版本
然后用命令行安装服务
服务面板里可以找到此服务
启动之,查看日志文件,服务运行正常

- 23:23:52,171 INFO -Configuration Result:
- [Success] Name QuartzTopShelfDemoService
- [Success] DisplayName QuartzTopShelfDemo服务
- [Success] Description Quartz+TopShelf实现Windows服务作业调度的一个示例Demo
- [Success] ServiceName QuartzTopShelfDemoService
- 23:23:52,185 INFO -Topshelf v3.3.154.0, .NET Framework v4.0.30319.34014
- 23:23:52,194 ERROR-The QuartzTopShelfDemoService service can only be installed as an administrator
- 23:25:54,758 INFO -Configuration Result:
- [Success] Name QuartzTopShelfDemoService
- [Success] DisplayName QuartzTopShelfDemo服务
- [Success] Description Quartz+TopShelf实现Windows服务作业调度的一个示例Demo
- [Success] ServiceName QuartzTopShelfDemoService
- 23:25:54,772 INFO -Topshelf v3.3.154.0, .NET Framework v4.0.30319.34014
- 23:25:54,781 DEBUG-Attempting to install 'QuartzTopShelfDemoService'
- 23:25:54,901 INFO -Installing QuartzTopShelfDemo服务 service
- 23:25:55,123 DEBUG-Opening Registry
- 23:25:55,123 DEBUG-Service path: "E:\DotNetProject\Y2016\QTDemo\QTDemo\bin\Release\QTDemo.exe"
- 23:25:55,123 DEBUG-Image path: "E:\DotNetProject\Y2016\QTDemo\QTDemo\bin\Release\QTDemo.exe" -displayname "QuartzTopShelfDemo服务" -servicename "QuartzTopShelfDemoService"
- 23:25:58,357 DEBUG-Closing Registry
- 23:28:10,442 INFO -Configuration Result:
- [Success] Name QuartzTopShelfDemoService
- [Success] DisplayName QuartzTopShelfDemo服务
- [Success] Description Quartz+TopShelf实现Windows服务作业调度的一个示例Demo
- [Success] ServiceName QuartzTopShelfDemoService
- 23:28:10,455 INFO -Topshelf v3.3.154.0, .NET Framework v4.0.30319.34014
- 23:28:10,649 DEBUG-Started by the Windows services process
- 23:28:10,649 DEBUG-Running as a service, creating service host.
- 23:28:10,651 INFO -Starting as a Windows service
- 23:28:10,654 DEBUG-[Topshelf] Starting up as a windows service application
- 23:28:10,657 INFO -[Topshelf] Starting
- 23:28:10,658 DEBUG-[Topshelf] Current Directory: E:\DotNetProject\Y2016\QTDemo\QTDemo\bin\Release
- 23:28:10,658 DEBUG-[Topshelf] Arguments:
- 23:28:10,940 INFO -[Topshelf] Started
- 23:28:10,988 INFO -TestJob测试
- 23:28:15,000 INFO -TestJob测试
- 23:28:20,000 INFO -TestJob测试

源码存网盘 quartz.net
qurtz.net(转载)的更多相关文章
- Crystal Clear Applied: The Seven Properties of Running an Agile Project (转载)
作者Alistair Cockburn, Crystal Clear的7个成功要素,写得挺好. 敏捷方法的关注点,大家可以参考,太激动所以转载了. 原文:http://www.informit.com ...
- RTP与RTCP协议介绍(转载)
RTSP发起/终结流媒体.RTP传输流媒体数据 .RTCP对RTP进行控制,同步.RTP中没有连接的概念,本身并不能为按序传输数据包提供可靠的保证,也不提供流量控制和拥塞控制,这些都由RTCP来负责完 ...
- 《Walking the callstack(转载)》
本文转载自:https://www.codeproject.com/articles/11132/walking-the-callstack Download demo project with so ...
- [转载]MVVM模式原理分析及实践
没有找到很好的MVVM模式介绍文章,简单找了一篇,分享一下.MVVM实现了UI\UE设计师(Expression Blend 4设计界面)和软件工程师的合理分工,在SilverLight.WPF.Wi ...
- [转载]:STM32为什么必须先配置时钟再配置GPIO
转载来源 :http://blog.csdn.net/fushiqianxun/article/details/7926442 [原创]:我来添两句,就是很多同学(包括我)之前搞低端单片机,到了stm ...
- [转载]从MyEclipse到IntelliJ IDEA-让你摆脱鼠标,全键盘操作
从MyEclipse转战到IntelliJ IDEA的经历 注转载址:http://blog.csdn.net/luoweifu/article/details/13985835 我一个朋友写了一篇“ ...
- TCP同步与异步,长连接与短连接【转载】
原文地址:TCP同步与异步,长连接与短连接作者:1984346023 [转载说明:http://zjj1211.blog.51cto.com/1812544/373896 这是今天看到的一篇讲到T ...
- 在CentOS 7/6.5/6.4 中安装Java JDK 8(转载)
转载在CentOS 7/6.5/6.4 中安装Java JDK 8 首先,在你的服务器上运行一下更新. yum update 然后,在您的系统上搜索,任何版本的已安装的JDK组件. rpm -qa | ...
- 用C#实现MD5的加密(转载)
方法一 首先,先简单介绍一下MD5 MD5的全称是message-digest algorithm 5(信息-摘要算法,在90年代初由mit laboratory for computer scien ...
随机推荐
- sqlserver 模糊查询,连表,聚合函数,分组
use StudentManageDB go select StudentName,StudentAddress from Students where StudentAddress like '天津 ...
- c#类的继承与包含的关系
基础例子 class Dept { private string name; private Emp emp; public string getName() { return this.name; ...
- BCGcontrolBar(二) 改变RIBBON字体
在xp系统下 BCGcontrolBar字体会发虚 这时候重新设置下字体就行了 在单文档的MainFram的onCreate中加入 CFont *font=m_wndRibbonBar.GetFont ...
- mybaits插入时的一些总结
我们时长在批量插入时,需要获取插入数据的id. 这样: <insert id="insertUser" parameterType="gys.entity.User ...
- Java GC2
虚拟机中共划分为3个代:年轻代,老年代,持久代:其中持久代主要存放Java类的类信息,与垃圾收集要收集的Java对象关系不大,年轻代和老年代的划分是对垃圾收集影响较大的 年轻代: HotSpot JV ...
- Hive 2.1.1安装配置
##前期工作 安装JDK 安装Hadoop 安装MySQL ##安装Hive ###下载Hive安装包 可以从 Apache 其中一个镜像站点中下载最新稳定版的 Hive, apache-hive-2 ...
- oracle 表或视图不存在
导入导出时,会自动表名自动加上了““双引号需要将表名改一下就可以了 alter table "oldtablename" rename to newtableName;
- 安装配置fastDFS文件服务器 - Linux
一.配置linux环境 1.新建虚拟机 把上次安装的CentOS7的文件复制一份,并改名 打开VM>打开虚拟机,选择刚才复制好的虚拟机,并启动.这样做的目的主要是为了保留一份最基础的母本,为了将 ...
- 通俗理解cookies,sessionStorage,localStorage的区别
sessionStorage .localStorage 和 cookie 之间的区别共同点:都是保存在浏览器端,且同源的. 区别:cookie数据始终在同源的http请求中携带(即使不需要),即co ...
- Ruby学习笔记2 : 一个简单的Ruby网站,搭建ruby环境
Ruby on Rails website 的基础是 请求-返回 循环. 首先是浏览器请求服务器, 第二步,Second, in our Rails application, the route ta ...