繁体   English   中英

在以编程方式管理的Quartz作业中注入Entity Manager

[英]Injecting Entity Manager in a programatically managed Quartz job

我有一种奇怪的要求。

我有一个使用JPA Hibernate的Spring托管应用程序。 我已经使用Quartz编写了一些作业类,但是它们没有与Spring框架一起管理/集成。 它们是独立的Java类,具有复杂的逻辑和基于运行时参数的动态触发计划。 因此,我通过LoginController以编程方式安排了这些作业。 现在,当我需要在这些作业类中执行一些数据库事务时,问题就来了。

如果我尝试执行@PersistenceContext private EntityManager实体管理器,则会得到一个空引用,该引用很清楚,因为我无法将这些组件自动连接到非Spring管理的Quartz作业中。

我不得不使用的最后一种方法是在作业类中对我的数据库事务使用JDBC,但这增加了工作量。 有没有可能解决我的问题。 我已经附加了Java代码以使事情变得清楚。

JobScheduler.java

public class JobScheduler extends Object
{
    private static final Logger logger = LoggerFactory
            .getLogger(JobScheduler.class);

    private static final JobScheduler s_instance = new JobScheduler();
    private static boolean s_isSchedulerStarted = false;
    private static Scheduler s_scheduler = null;

    static
    {
        try
        {
            s_scheduler = new StdSchedulerFactory().getScheduler();
        } catch (SchedulerException e)
        {
            logger.debug(e.getMessage().toString());
        }
    }

    public static JobScheduler getInstance()
    {
        if (!s_isSchedulerStarted)
        {
            try
            {
                s_scheduler.start();
                s_isSchedulerStarted = true;
            } catch (SchedulerException e)
            {
                logger.debug(e.getMessage());
                e.printStackTrace();
            }
        }
        return s_instance;
    }

    public Scheduler getScheduler()
    {
        return s_scheduler;
    }

    public void scheduleMonitoring() throws ApplicationException
    {
        try
        {
            Class<? extends Job> jobClass = ScheduleMonitoringJob.class;
            JobDetail job = JobBuilder.newJob(jobClass).build();
            Trigger trigger = ScheduleMonitoringJob.getTriggerWithSchedule();
            s_scheduler.scheduleJob(job, trigger);

        } catch (SchedulerException e)
        {
            logger.debug(e.getMessage());
            throw new ApplicationException(e);
        }
    }

}

ScheduleMonitoringJob.java

public class ScheduleMonitoringJob implements InterruptableJob
{
    private static final Logger logger = LoggerFactory
            .getLogger(ScheduleMonitoringJob.class);

    @PersistenceContext
    private EntityManager entityManager; //THIS COMES AS NULL 

    /*
     * (non-Javadoc)
     * 
     * @see org.quartz.Job#execute(org.quartz.JobExecutionContext)
     */
    @Override
    public void execute(JobExecutionContext context)
            throws JobExecutionException
    {
        List<KpiDefinition> kpisToBeMonitored = getNewOrChangedKPIs();

        for (KpiDefinition kpiDef : kpisToBeMonitored)
        {
            KpiType kpiType = kpiDef.getKpiTypeBean();
            Class<? extends MonitorJob> jobClass = null;

            if (kpiType.getName()
                    .equalsIgnoreCase(KpiType.TYPE_DB_CONNECTIVITY))
            {
                jobClass = DBConnectionMonitorJob.class;
            } else if (kpiType.getName().equalsIgnoreCase(
                    KpiType.TYPE_FTP_SERVER_AVAILABILITY))
            {
                jobClass = FTPServerMonitorJob.class;
            } else if (kpiType.getName().equalsIgnoreCase(
                    KpiType.TYPE_SOAP_SERVICE_AVAILABILITY))
            {
                jobClass = SOAPServiceMonitorJob.class;
            } else
            {
                jobClass = EngineEventSQLMonitorJob.class;
            }

            JobDetail job = JobBuilder.newJob(jobClass).build();

            job.getJobDataMap().put("kpiDefId", kpiDef.getKpiDefId());

            Trigger trigger = MonitorJob.getTriggerWithSchedule(kpiDef);

            try
            {
                JobScheduler.getInstance().getScheduler()
                        .scheduleJob(job, trigger);
            } catch (SchedulerException e)
            {
                logger.debug(e.getMessage());
                throw new JobExecutionException(e);
            }

            kpiDef.setKpiStatus(KpiDefinition.KPI_STATUS_PROCESSING_PROCESSED);

        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.quartz.InterruptableJob#interrupt()
     */
    @Override
    public void interrupt() throws UnableToInterruptJobException
    {
        // TODO Auto-generated method stub

    }

    public static Trigger getTriggerWithSchedule()
    {
        SimpleTrigger trigger = (SimpleTrigger) newTrigger().withSchedule(
                SimpleScheduleBuilder.repeatMinutelyForever(10)).build();

        return trigger;

    }

    public List<KpiDefinition> getNewOrChangedKPIs()
    {
        String[] statusCodes = { KpiDefinition.KPI_STATUS_NEW,
                KpiDefinition.KPI_STATUS_CHANGED };
        Query query = entityManager
                .createQuery("select kpiDef from KpiDefinition kpiDef where kpiDef.kpiStatus in (:statusCodes)");
        query.setParameter("statusCodes", statusCodes);
        return query.getResultList();
    }
}

由于您在应用程序中使用过Spring,因此强烈建议您使用Spring SchedulerFactoryBean创建Quartz Scheduler实例。 然后,您可以像这样轻松地访问Spring应用程序上下文(以及已经由Spring管理的EntityManager):

public class ScheduleMonitoringJob implements InterruptableJob
{
    private static final String SCHEDULER_CONTEXT_APPLICATION_CONTEXT_KEY = "applicationContext";

    ...

    /**
     * Returns the {@link ApplicationContext} instance extracted from the scheduler context, or null if not found.
     *
     * @return the {@link ApplicationContext} instance.
     */
    protected EntityManager getEntityManager(JobExecutionContext context)
    {
      try
      {
        ApplicationContext springCtx = (ApplicationContext) context.getScheduler().getContext().get( SCHEDULER_CONTEXT_APPLICATION_CONTEXT_KEY );

        return springCtx.getBean(EntityManager.class);
      }
      catch ( SchedulerException e )
      {
        if ( log.isErrorEnabled() )
          log.error( "Error obtaining Spring application context.", e );

        return null;
      }
    }
}

Spring应用程序上下文示例。 请注意applicationContextSchedulerContextKey属性的值,该值包含Quartz作业应用程序上下文属性名称的名称,工厂将Spring应用程序上下文存储在该名称中:

  <!--
    Quartz scheduler.
  -->
  <bean id="scheduler"
        class="org.springframework.scheduling.quartz.SchedulerFactoryBean">

    <property name="schedulerName" value="MyScheduler"/>

    ...

    <!--
      Name of the Quartz scheduler context property where the factory stores the Spring context.
    -->
    <property name="applicationContextSchedulerContextKey" value="applicationContext"/>
  </bean>

如果您不想迁移代码以使用Spring SchedulerFactoryBean,则可以使用以下方法实现相同的结果:

    public class JobScheduler extends Object
    {       
        private static final JobScheduler s_instance = new JobScheduler();
        private static boolean s_isSchedulerStarted = false;
        private static Scheduler s_scheduler = null;

        static
        {
            try
            {
                s_scheduler = new StdSchedulerFactory().getScheduler();
                s_scheduler.getContext().put("applicationContext", YOUR_SPRING_APPLICATION_CONTEXT);
            } 
            catch (SchedulerException e)
            {
                ...
            }
        }

        ...
    }

另外,您可以在其中存储EntityManager实例,而不是将Spring应用程序上下文存储在JobScheduler类的Quartz调度程序上下文中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM