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配置文件,可直接使用
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>
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测试