Quartz.net 2.x 学习笔记03-使用反射加载定时任务
将定时任务信息存储在XML文件中,使用反射加载定时任务
首先新建一个MVC的空站点,使用NuGet添加对Quartz.net和Common.Logging.Log4Net1213的引用,同时使用NuGet管理器控制台执行命令更新log4net,PM> update-package log4net
接着在解决方案中添加一个类库Library项目
类库项目也添加对Quartz.net的引用
下面可以编写代码了,在Library类库中添加一个JobBase类,3个Job类,和一个Job管理类(假设分别取名:JobBase.cs,HelloJob.cs,AnotherJob.cs,ParameterJob.cs,JobManage.cs)
注:HelloJob、AnotherJob、ParameterJob都是任务类继承自JobBase并实现IJob接口
它们的代码分别如下:
1、JobBase.cs
using Common.Logging; namespace JobLibrary { public class JobBase { /// <summary> /// JOB状态日志 /// </summary> protected internal static readonly ILog jobStatus = LogManager.GetLogger("JobLogAppender"); /// <summary> /// 服务错误日志 /// </summary> protected internal static readonly ILog serviceErrorLog = LogManager.GetLogger("JobLogAppender"); } }
2、HelloJob.cs
using Quartz; namespace JobLibrary { public class HelloJob:JobBase,IJob { public void Execute(IJobExecutionContext context) { try { MyExecMethod(); } catch (Exception ex) { serviceErrorLog.Info(string.Concat("HelloJob执行出错:", ex.StackTrace)); } } public void MyExecMethod() { jobStatus.Info("我正在执行HelloJob的代码,此为测试,只是写日志"); } } }
3、AnotherJob.cs
using Quartz; namespace JobLibrary { public class AnotherJob:JobBase,IJob { public void Execute(IJobExecutionContext context) { try { DoSomething(); } catch (Exception ex) { serviceErrorLog.Info(string.Concat("AnotherJob执行出错:", ex.StackTrace)); } } public void DoSomething() { jobStatus.Info("我正在执行AnotherJob的代码,此为测试,只是写日志"); } } }
4、ParameterJob.cs (传参数到Job中)
using Quartz; namespace JobLibrary { public class ParameterJob:JobBase,IJob { private static int a = 1; public void Execute(IJobExecutionContext context) { try { if (!context.JobDetail.JobDataMap.Contains("a")) //判断是否有a参数 { context.JobDetail.JobDataMap.Add("a", a); } else { context.JobDetail.JobDataMap["a"] = a; } DoSomething(); jobStatus.Info("a=" + a); //打印a的值 a++; } catch (Exception ex) { serviceErrorLog.Info(string.Concat("ParameterJob执行出错:", ex.StackTrace)); } } public void DoSomething() { jobStatus.Info("我正在执行ParameterJob的代码,此为测试,只是写日志"); } } }
5、JobManage.cs
说明:JobManage相当于一个助手类,本来应该和上面的任务类分开单独放在另一类库中,
为了不增加额外的代码就放在一起了(因为使用反射加载Job,相当于所有的任务和Web应用程序是可以隔离开的)
using Common.Logging; using Quartz; using Quartz.Impl; using System.Xml.Linq; using System.IO; using Quartz.Impl.Triggers; using System.Reflection; namespace JobLibrary { public class JobManage { private static ISchedulerFactory sf = new StdSchedulerFactory(); private static IScheduler scheduler; static readonly ILog errorLog = LogManager.GetLogger("JobLogAppender"); //开启定时器 public static void StartScheduleFromConfig() { string currentDir = AppDomain.CurrentDomain.BaseDirectory; try { string dllPath = Path.Combine(currentDir, "JobScheduler.config"); //定时任务信息的配置文件 XDocument xDoc = XDocument.Load(dllPath); var jobScheduler = from x in xDoc.Descendants("JobScheduler") select x; var jobs = jobScheduler.Elements("Job"); XElement jobDetailXElement, triggerXElement; scheduler = sf.GetScheduler(); //StdSchedulerFactory工厂取得一个默认的调度器 CronTriggerImpl cronTrigger; foreach (var job in jobs) { //加载程序集joblibaray (反射加载应用程序bin目录下的JobLibrary.dll) Assembly ass = Assembly.LoadFrom(Path.Combine(currentDir + "\\bin\\", job.Element("DllName").Value)); jobDetailXElement = job.Element("JobDetail"); //Job的Detail信息 triggerXElement = job.Element("Trigger"); //Job的触发器信息 JobDetailImpl jobDetail = new JobDetailImpl(jobDetailXElement.Attribute("job").Value, jobDetailXElement.Attribute("group").Value, ass.GetType(jobDetailXElement.Attribute("jobtype").Value)); if (triggerXElement.Attribute("type").Value.Equals("CronTrigger")) { cronTrigger = new CronTriggerImpl(triggerXElement.Attribute("name").Value, triggerXElement.Attribute("group").Value, triggerXElement.Attribute("expression").Value); scheduler.ScheduleJob(jobDetail, cronTrigger); } } //开启定时器 scheduler.Start(); } catch (Exception e) { errorLog.Error(e.StackTrace); } } //关闭定时器 public static void ShutDown() { if (scheduler != null && !scheduler.IsShutdown) { scheduler.Shutdown(); } } /** * 修改任务的执行周期 */ public static void ModifyJobTime(string jobKey,string jobGroup,string triggerKey,string triggerGroup, String time) { try { //获取trigger TriggerKey triKey = new TriggerKey(triggerKey, triggerGroup); ITrigger trigger = scheduler.GetTrigger(triKey); //表达式调度构造器 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.CronSchedule(time); //按新的cronExpression表达式重新构建trigger trigger = trigger.GetTriggerBuilder().WithIdentity(triggerKey).WithSchedule(scheduleBuilder).Build(); //按新的trigger重新设置job执行 scheduler.RescheduleJob(triKey, trigger); } catch (Exception e) { errorLog.Error(e.StackTrace); } } } }
接下来和02笔记一样:
1、Web应用程序添加对JobLibrary的引用
2、配置好Web.config文件
<configSections> <!--配置Common.Logging节点--> <sectionGroup name="common"> <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" /> </sectionGroup> <!--Log4net--> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/> </configSections> <common> <logging> <!--1.此Adapter只输出到控制台,如果是用的控制台,用这个输出--> <!-- <factoryAdapter type="Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter, Common.Logging"> <arg key="level" value="INFO" /> <arg key="showLogName" value="true" /> <arg key="showDataTime" value="true" /> <arg key="dateTimeFormat" value="yyyy/MM/dd HH:mm:ss:fff" /> </factoryAdapter>--> <!--2.此Adapter只输出到Log4.net的配置文件所指定的地方--> <factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4Net1213"> <!--FILE,FILE-WATCH,INLINE,EXTERNAL--> <arg key="configType" value="FILE" /> <arg key="configFile" value="~/log4net.config" /> <!-- 指定log4net的配置文件名称 --> <arg key="level" value="Warn" /> </factoryAdapter> </logging> </common>
3、增加log4net.config配置文件
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" /> </configSections> <appSettings> </appSettings> <log4net> <!--定义输出到文件中--> <appender name="JobLogAppender" type="log4net.Appender.RollingFileAppender"> <!--输出日志文件的路径--> <file value="Log\XXLog.log" /> <!--输出日志时自动向后追加--> <appendToFile value="true" /> <!--防止多线程时不能写Log,官方说线程非安全,但实际使用时,本地测试正常,部署后有不能写日志的情况--> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <!--置为true,当前最新日志文件名永远为file节中的名字--> <staticLogFileName value="false" /> <!--日志以大小作为备份样式,还有一种方式是Date(日期)--> <rollingStyle value="size" /> <countDirection value="-1" /> <!--单个日志的最大容量,(可用的单位:KB|MB|GB)不要使用小数,否则会一直写入当前日志--> <maximumFileSize value="1MB" /> <!--日志最大个数,都是最新的--> <maxSizeRollBackups value="10" /> <datePattern value='"."yyyy-MM-dd".log"' /> <layout type="log4net.Layout.PatternLayout"> <!--每条日志末尾的文字说明--> <footer value="**************************************************************" /> <!--输出格式--> <!--样例:2008-03-26 13:42:32,111 [10] INFO Log4NetDemo.MainClass - info--> <conversionPattern value="%newline%d{yyyy/MM/dd,HH:mm:ss.fff},[%-5level] Message:%message%newline" /> </layout> </appender> <root> <!--文件形式记录日志--> <appender-ref ref="JobLogAppender" /> <level value="INFO"></level> </root> </log4net> </configuration>
4、添加JobScheduler.config任务的配置文件
<?xml version="1.0" encoding="utf-8" ?> <JobScheduler> <Job Description="作业1"> <DllName>JobLibrary.dll</DllName> <JobDetail job="HelloJob" group="HelloGroup" jobtype="JobLibrary.HelloJob" /> <Trigger name="HelloJob" group="HelloGroup" type="CronTrigger" expression="0/10 * * * * ?" /> </Job> <Job Description="作业2"> <DllName>JobLibrary.dll</DllName> <JobDetail job="Another" group="AnotherGroup" jobtype="JobLibrary.AnotherJob" /> <Trigger name="Another" group="AnotherGroup" type="CronTrigger" expression="0/5 * * * * ?" /> </Job> <Job Description="作业3"> <DllName>JobLibrary.dll</DllName> <JobDetail job="Parameter" group="ParameterGroup" jobtype="JobLibrary.ParameterJob" /> <Trigger name="Parameter" group="ParameterGroup" type="CronTrigger" expression="0/3 * * * * ?" /> </Job> </JobScheduler>
5、添加HomeController以前Index方法的视图
程序最后的目录结构:
最后修改Global.asax文件代码:
using JobLibrary; namespace Quartz003 { // 注意: 有关启用 IIS6 或 IIS7 经典模式的说明, // 请访问 http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); //启动定时任务 JobManage.StartScheduleFromConfig(); } protected void Application_End(object sender, EventArgs e) { //关闭定时任务 JobManage.ShutDown(); } } }
编译运行应用程序,找到应用程序目录Log文件夹下的XXLog.log文件