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文件

源码下载(微云)

时间: 2024-11-10 08:16:48

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

Openstack学习笔记之——Neutron-server服务加载与启动源码分析(三)

本文是在学习Openstack的过程中整理和总结,由于时间和个人能力有限,错误之处在所难免,欢迎指正! 在Neutron-server服务加载与启动源码分析(二)中搞定模块功能的扩展和加载,我们就回到Neutron-server服务加载与启动源码分析(一)中的_run_wsgi函数 <span style="font-size:14px;">def _run_wsgi(app_name): app = config.load_paste_app(app_name) ifno

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

在项目开发的过程中,因为无法和后台的数据做交互,所以我们可以自建一个假数据文件(如data.json)到项目文件夹中,这样我们就可以模仿后台的数据进行开发.但是,如何在一个vue.js 项目中引入本地的json文件呢,下面就将步骤贴出来.(此时项目是由webpack打包而成). 整个项目是由webpack打包而成,具体步骤上网查找.具体项目结构如下: 1:我们找到bulid>dev-server.js,然后打开 2:在里面加入这段代码. var app = express() var appDa

(Object-C)学习笔记 --OC的懒加载和单例方法

OC的懒加载 什么是懒加载: 懒加载——也称为延迟加载,即在需要的时候才加载(效率低,占用内存小).所谓懒加载,写的是其get方法. 注意:如果是懒加载的话则一定要注意先判断是否已经有了,如果没有那么再去进行实例化. 懒加载的好处 (1)不必将创建对象的代码全部写在viewDidLoad方法中,代码的可读性更强 (2)每个控件的getter方法中分别负责各自的实例化处理,代码彼此之间的独立性强,松耦合 懒加载的例子: #import "MusicTableViewController.h&quo

Laravel 学习笔记之 Composer 自动加载

说明:本文主要以Laravel的容器类Container为例做简单说明Composer的自动加载机制. Composer的自动加载机制 1.初始化一个composer项目 在一个空目录下composer安装Laravel的容器Container包: composer require illuminate/container 然后在该目录下新建一个index.php文件,然后分析下Container类为何能被实例化: <?php /** * Created by PhpStorm. * User:

4月6日学习笔记——如何提高网页加载速度(前端面试考点)

网页的加载速度是评估网站质量一个重要指标.原因在于大多数用户能够容忍的网页加载时间只有几秒,如果超出了访客的忍受范围他们会毫不留情地关掉你的网 页,所以网页载入速度会极大地影响网站的流量和访问.以下总结了几种可以明显提高网站加载速度的初步简单技巧方式,如果你的网站存在载入速度慢的问题不妨 与此为参考对网页做些初步优化. 网页加载提速之 – 优化网页图片文件 你的网页一定有图片,加载一个网页往往图片的总尺寸是最大的,特别是那些颜色丰富的背景图片和大副广告图片.所以一般要在同等图片质量的情况下要尽可

Unity学习笔记13——代码动态加载Prefab预设体

在进行一些功能开发的时候,我们常常将一些能够复用的对象制作成.prefab的预设物体,然后将预设体存放到Resources目录之下,使用时再动态加载到场景中并进行实例化.例如:子弹.特效甚至音频等,都能制作成预设体. 一.预设动态加载到场景: 一个预设体要能够通过代码控制在场景中进行显示,需要三个步骤,这里我们以动态加载怪物血条为例子分析一个常见的误区: 1.预设体资源加载: //加载预设体资源 GameObject hp_bar = (GameObject)Resources.Load("Pr

Quartz.NET 2.0 学习笔记(1) :Quartz.NET简介

转自:http://www.cnblogs.com/lzrabbit/archive/2012/04/13/2447609.html Quartz.NET 项目地址 http://quartznet.sourceforge.net/ Quartz.NET 2.0 学习笔记(1) :Quartz.NET简介 Quartz.NET 2.0 学习笔记(2) :和1.0的几点不同 Quartz.NET 2.0 学习笔记(3) :通过配置文件实现任务调度 Quartz.NET 2.0 学习笔记(4) :c

python学习笔记(03):函数

默认参数值:   只有在行参表末尾的哪些参数可以有默认参数值,即 def func(a, b=5 )#有效的 def func( a=5,b )#无效的 关键参数: #!/usr/bin/python # Filename: func_key.py def func(a, b=5, c=10): print 'a is', a, 'and b is', b, 'and c is', c func(3, 7) func(25, c=24) func(c=50, a=100) #输出: $ pyth

HTTP 学习笔记03

通用信息头 Cache-Control : no-cache(不缓存当前请求) [*] Connection:close(返回当前请求后立即断开)[*] Date:...(HTTP消息产生的时间) Pragma:no-cache (不缓存) [*] Trailer:Date(哪些能放到实体内容后的头字段) Transfer-Encoding:chunked (指定传输编码方式)[*] Upgrade:HTTP/2.0,SHTTP/1.3 (支持的版本) Via:HTTP/1.1 Proxy1,H