Quartz.net 2.x 学习笔记03-使用反射加载定时任务

时间:2023-03-09 00:57:57
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 = ; 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方法的视图

程序最后的目录结构:

Quartz.net 2.x 学习笔记03-使用反射加载定时任务

最后修改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文件

Quartz.net 2.x 学习笔记03-使用反射加载定时任务

源码下载(微云)