开发者

Injecting properties into a QuartzJobObject

开发者 https://www.devze.com 2023-04-07 04:07 出处:网络
Am I right in thinking that my QuartzJobObject can\'t have any DAO\'s or other Spring-managed objects injected into it?

Am I right in thinking that my QuartzJobObject can't have any DAO's or other Spring-managed objects injected into it?

Was hoping I could do something like this (orderService is what I want to inject):

<object name="checkPendingOrdersJob" type="Spring.Scheduling.Quartz.JobDetailObject, Spring.Scheduling.Quartz">
  <property name="JobType" value="Munch.ScheduledTasks.CheckPendingOrdersJob" />
  <!-- W开发者_Go百科e can inject values through JobDataMap -->
  <property name="JobDataAsMap">
    <dictionary>
      <!--entry key="UserName" value="Alexandre" /-->
    </dictionary>      
  </property>
  <property name="orderService" ref="orderService"/>
</object>

...which I know doesn't make sense because of the type it is. But, I could do with being able to inject some DAO's, Services etc somehow. I can't figure it out though. How can I do this?


This is what I've ended up with and it works perfectly (hopefully useful to someone else)

Job factory that is aware of Spring's context

/// <summary>
/// A custom job factory that is aware of the spring context
/// </summary>
public class ContextAwareJobFactory : AdaptableJobFactory, IApplicationContextAware
{
    /// <summary>
    /// The spring app context
    /// </summary>
    private IApplicationContext m_Context;

    /// <summary>
    /// Set the context
    /// </summary>
    public IApplicationContext ApplicationContext
    {
        set
        {
            m_Context = value;
        }
    }

    /// <summary>
    /// Overrides the default version and sets the context
    /// </summary>
    /// <param name="bundle"></param>
    /// <returns></returns>
    protected override object CreateJobInstance(TriggerFiredBundle bundle)
    {
        return m_Context.GetObject(bundle.JobDetail.JobType.Name, bundle.JobDetail.JobType);
    }
}

The job itself (checks the DB for records and if there are at least HomeManyMenuItemsIsOK of them, everything is good). Note: menuService is an injected spring-managed object that itself has several DAO's in it). HowManyMenuItemsIsOK is a static property that's passed in through the job data map.

public class CheckMenuIsHealthyJob : QuartzJobObject 
{
    private static readonly ILog log = LogManager.GetLogger(typeof(CheckMenuIsHealthyJob));

    public IMenuService menuService { get; set; }
    public int HowManyMenuItemsIsOK { get; set; }

    /// <summary>
    /// Check how healthy the menu is by seeing how many menu items are stored in the database. If there
    /// are more than 'HowManyMenuItemsIsOK' then we're ok.
    /// </summary>
    /// <param name="context"></param>
    protected override void ExecuteInternal(JobExecutionContext context)
    {
        IList<MenuItem> items = menuService.GetAllMenuItems();
        if (items != null && items.Count >= HowManyMenuItemsIsOK)
        {
            log.Debug("There are " + items.Count + " menu items. Menu is healthy!");
        }
        else
        {
            log.Warn("Menu needs some menu items adding!");
        }

    }
}

And finally the Spring config

<!-- Scheduled Services using Quartz -->
  <!-- This section contains Quartz config that can be reused by all our Scheduled Tasks ---->  
  <!-- The Quartz scheduler factory -->
  <object id="quartzSchedulerFactory" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz">
    <!-- Tell Quartz to use our custom (context-aware) job factory -->
    <property name="JobFactory" ref="contextAwareJobFactory"/>

    <!-- Register the triggers -->
    <property name="triggers">
      <list>
        <ref object="frequentTrigger" />
      </list>
    </property>
  </object>  

  <!-- Funky new context-aware job factory -->
  <object name="contextAwareJobFactory" type="Munch.Service.ScheduledTasks.ContextAwareJobFactory" />

  <!-- A trigger that fires every 10 seconds (can be reused by any jobs that want to fire every 10 seconds) -->
  <object id="frequentTrigger" type="Spring.Scheduling.Quartz.CronTriggerObject, Spring.Scheduling.Quartz" lazy-init="true">
    <property name="jobDetail" ref="checkMenuIsHealthyJobDetail" />
    <property name="cronExpressionString" value="0/10 * * * * ?" />
  </object>  

  <!-- Now the job-specific stuff (two object definitions per job; 1) the job and 2) the job detail) --> 
  <!-- Configuration for the 'check menu is healthy job' -->
  <!-- 1) The job -->
  <object name="checkMenuIsHealthyJob" type="Munch.Service.ScheduledTasks.CheckMenuIsHealthyJob" singleton="false">
    <property name="menuService" ref="menuService"/>
  </object>

  <!-- 2) The job detail -->
  <object name="checkMenuIsHealthyJobDetail" type="Spring.Scheduling.Quartz.JobDetailObject, Spring.Scheduling.Quartz">
    <property name="JobType" value="Munch.Service.ScheduledTasks.CheckMenuIsHealthyJob"/>
    <property name="JobDataAsMap">
      <dictionary>
        <entry key="HowManyMenuItemsIsOK" value="20" />
      </dictionary>
    </property>    
  </object>


You can do property/constructor injection into your job by overiding CreateJobInstance of AdaptableJobFactory and register your new JobFactory instead of the default one.

The passed in TriggerFiredBundle provides you with enough infos to ask the context for a matching job (based on conventions). bundle.JobDetail.JobType.Name and bundle.JobDetail.JobType fitted my need, so back in 2008 I ended up with sth. like this (the class is derived form AdaptableJobFactory and implements IApplicationContextAware to get the context injected):

public class ContextAwareJobFactory : AdaptableJobFactory, IApplicationContextAware
{
  private IApplicationContext m_Context;

  public IApplicationContext ApplicationContext
  {
    set
    {
      m_Context = value;
    }
  }

  protected override object CreateJobInstance( TriggerFiredBundle bundle )
  {
    return m_Context.GetObject( bundle.JobDetail.JobType.Name, bundle.JobDetail.JobType );
  }
}

You need to register the ContextAwareJobFactory using the following config:

<objects xmlns="http://www.springframework.net">
  <!-- Some simple dependency -->
  <object name="SomeDependency" type="Namespace.SomeDependency, Assembly" />

  <!-- The scheduled job, gets the dependency. -->
  <object name="ExampleJob" type="Namespace.ExampleJob, Assembly" singleton="false">
    <constructor-arg name="dependency" ref="SomeDependency"/>
  </object>

  <!-- The JobDetail is configured as usual. -->
  <object name="ExampleJobDetail" type="Spring.Scheduling.Quartz.JobDetailObject, Spring.Scheduling.Quartz">
    <property name="JobType" value="Namespace.ExampleJob, Assembly"/>        
  </object>

  <!-- The new JobFactory. -->
  <object name="ContextAwareJobFactory" type="Namespace.ContextAwareJobFactory, Assembly" />

  <!-- Set the new JobFactory onto the scheduler factory. -->
  <object id="quartzSchedulerFactory" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz">
    <property name="JobFactory" ref="ContextAwareJobFactory"/>
  </object>      
</objects>

I don't know if there is sth. ootb since this was developed in 2008 and I did not followed the integration progress made for quartz.net.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号