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

将定时任务信息存储在XML文件中,使用反射加载定时任务

 

首先新建一个MVC的空站点,使用NuGet添加对Quartz.netCommon.Logging.Log4Net1213的引用,同时使用NuGet管理器控制台执行命令更新log4netPM> update-package log4net

 

接着在解决方案中添加一个类库Library项目

 

类库项目也添加对Quartz.net的引用

 

下面可以编写代码了,在Library类库中添加一个JobBase类,3Job类,和一个Job管理类(假设分别取名:JobBase.csHelloJob.csAnotherJob.csParameterJob.csJobManage.cs

 

注:HelloJobAnotherJobParameterJob都是任务类继承自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文件

 

源码下载(微云)

 

 

 

 

posted @ 2014-12-10 12:34  漫漫江雪  阅读(767)  评论(1编辑  收藏  举报