将定时任务信息存储在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方法的视图

程序最后的目录结构:

最后修改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-使用反射加载定时任务的更多相关文章

  1. [置顶] iOS学习笔记47——图片异步加载之EGOImageLoading

    上次在<iOS学习笔记46——图片异步加载之SDWebImage>中介绍过一个开源的图片异步加载库,今天来介绍另外一个功能类似的EGOImageLoading,看名字知道,之前的一篇学习笔 ...

  2. Flutter学习笔记(19)--加载本地图片

    如需转载,请注明出处:Flutter学习笔记(19)--加载本地图片 上一篇博客正好用到了本地的图片,记录一下用法: 首先新建一个文件夹,这个文件夹要跟目录下 然后在pubspec.yaml里面声明出 ...

  3. XV6学习笔记(1) : 启动与加载

    XV6学习笔记(1) 1. 启动与加载 首先我们先来分析pc的启动.其实这个都是老生常谈了,但是还是很重要的(也不知道面试官考不考这玩意), 1. 启动的第一件事-bios 首先启动的第一件事就是运行 ...

  4. [OpenCV学习笔记3][图像的加载+修改+显示+保存]

    正式进入OpenCV学习了,前面开始的都是一些环境搭建和准备工作,对一些数据结构的认识主要是Mat类的认识: [1.学习目标] 图像的加载:imread() 图像的修改:cvtColor() 图像的显 ...

  5. vue.js学习笔记(二):如何加载本地json文件

    在项目开发的过程中,因为无法和后台的数据做交互,所以我们可以自建一个假数据文件(如data.json)到项目文件夹中,这样我们就可以模仿后台的数据进行开发.但是,如何在一个vue.js 项目中引入本地 ...

  6. 【OpenCV学习笔记之一】图像加载,修改及保存

    加载图像(用cv::imread)imread功能是加载图像文件成为一个Mat对象 其中第一个参数表示图像文件名称第二个参数 表示加载的图像是什么类型 支持常见的三个参数值IMREAD_UNCHANG ...

  7. WMS学习笔记:1.尝试加载WMS

    1.首先找一个可用的WMS栅格地图服务:http://demo.cubewerx.com/demo/cubeserv/cubeserv.cgi 获取GetCapabilities: http://de ...

  8. Android学习笔记_51_转android 加载大图片防止内存溢出

    首先来还原一下堆内存溢出的错误.首先在SD卡上放一张照片,分辨率为(3776 X 2520),大小为3.88MB,是我自己用相机拍的一张照片.应用的布局很简单,一个Button一个ImageView, ...

  9. Android学习笔记_36_ListView数据异步加载与AsyncTask

    一.界面布局文件: 1.加入sdcard写入和网络权限: <!-- 访问internet权限 --> <uses-permission android:name="andr ...

随机推荐

  1. echarts3结合openlayers2实现Map类型图表

    网上查阅了部分资料,有些是用echarts2实现的,因echarts2无法满足项目中其他部分的要求,故只能采用echarts3(2017/9/18,echarts3官网突然把基于geo的demo下架了 ...

  2. 不常用的gcd公式

    gcd(a^m-b^m,a^n-b^n)=a^(gcd(m,n))-b^(gcd(m,n))

  3. RabbitMQ 简单了解以及使用

    RabbitMQ 开发语言:Erlang – 面向并发的编程语言. AMQP:是消息队列的一个协议. mysql 是 java 写的吗?不是 那么 java 能不能访问?可以,则通过(驱动)协议;那么 ...

  4. 一些C语言里面的编程

    C语言的知识还是不要忘的好: 1.求最大公约数的函数: #include <stdio.h> #define min(a,b) (a)>(b)?(b):(a) int gcd(int ...

  5. css tips —— 神奇的max-width,min-width, width覆盖规则

    max-width在比width小时,即使width使用!important来加权,仍会max-width生效: max-width比min-width小时,width < min-width, ...

  6. jsp:xpath - xml

    .1 关于“/ ”和“// ”的使用“/”是表示当前文档的节点,类似 DOS 目录分割符,“//”则表示当前文档所有的节点.类似查看整个目录.(1)/authors/author:表示选择根目录下.父 ...

  7. MVVM架构说明1

    MVVM是Model-View-ViewModel的简写.微软的WPF带来了新的技术体验,如Sliverlight.音频.视频.3D.动画……,这导致了软件UI层更加细节化.可定制化.同时,在技术层面 ...

  8. hdu 5265

    http://acm.hdu.edu.cn/showproblem.php?pid=5256 题目不错,题面忍不住骂一句mmp.......后面说ai都是正整数,我以为修改后也必须是正整数,前面又说只 ...

  9. 51nod 1326 奇妙的spfa+dp

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1326 1326 遥远的旅途 题目来源: TopCoder 基准时间限制: ...

  10. Linux:配置Linux网络和克隆虚拟机并更改配置

    Linux学习笔记1:配置Linux网络和克隆虚拟机并更改配置   一.配置Linux网络 在安装Linux的时候,一定要保证你的物理网络的IP是手动设置的,要不然会在Linux设置IP连通网络的时候 ...