将定时任务信息存储在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. JAVA集合类汇总 - 转载

    一.集合与数组 数组(可以存储基本数据类型)是用来存现对象的一种容器,但是数组的长度固定,不适合在对象数量未知的情况下使用. 集合(只能存储对象,对象类型可以不一样)的长度可变,可在多数情况下使用. ...

  2. html checkbox多选框语法与结构

    <input name="Fruit" type="checkbox" value="" /> 用法用例 <foreach ...

  3. StrStr,判断一个字符串是不是另一个字符串的字串,并返回子串的位置

    public int strStr(String haystack, String needle) { if(haystack == null || needle == null) { return ...

  4. viewport简介

    Viewport的用处:手机拥有了浏览器的初期,人们并没有专门为移动设备设计页面,造成的直接结果就是,访问的页面是直接将电脑页面进行缩放,操作起来有诸多不便,viewport就是用来解决这个问题的 1 ...

  5. URL的编码

    + URL 中+号表示空格 %2B 空格 URL中的空格可以用+号或者编码 %20 / 分隔目录和子目录 %2F ? 分隔实际的 URL 和参数 %3F % 指定特殊字符 %25 # 表示书签 %23 ...

  6. JSP静态包含和动态包含的区别和联系

    JSP页面的静态包含和动态包含 JSP中有两种包含:静态包含:<%@include file="被包含页面"%>和动态包含: <jsp:include page= ...

  7. Java实现数组去除重复数据的方法详解

    一.用List集合实现 int[] str = {5, 6, 6, 6, 8, 8, 7,4}; List<Integer> list = new ArrayList<Integer ...

  8. c语言中的string

    1. strlen(char const* s); 函数传入的是c风格字符串(即以‘\0’结尾的字符数组),返回的长度为size_t(即unsigned int),其长度不包括'\0'. 2. str ...

  9. CSS:Tutorial three

    1.CSS Links links can be styled differently depending on what state they are in. The four links stat ...

  10. L138 Cryptocurrency Exchanges at Risk of Manipulation

    Several cryptocurrency exchanges are plagued by poor market surveillance, pervasive conflicts of int ...