在程序化管理的Quartz作业中注入Entity Manager [英] Injecting Entity Manager in a programatically managed Quartz job

查看:68
本文介绍了在程序化管理的Quartz作业中注入Entity Manager的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有点奇怪.

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

I have a Spring managed application uisng JPA Hibernate. I have written few job classes using Quartz but they are not managed/integrated with Spring framework. They are kind of independent java classes with complex logic and dynamic triggering schedules based on run time parameters. So I schedule these jobs programatically from the LoginController. Now the problem comes when I need to do some database transactions in these job classes.

如果我尝试做 @PersistenceContext 私有EntityManager实体管理器 我得到了一个空引用,它很清楚,因为我无法将这些组件自动连接到非Spring管理的Quartz作业中.

If I try to do @PersistenceContext private EntityManager entityManager I get a null reference which is clear because I am not able to autowire these components into non spring managed Quartz jobs.

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

The last resort that I would have to use is to use JDBC for my database transactions in the job classes but that increases the work manifold. Is there any possible solution to my problem. I have attached the java code to make things clear.

JobScheduler.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

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):

Since you write that you are using Spring in your application, I strongly recommend that you use the Spring SchedulerFactoryBean to create the Quartz scheduler instance. Then you can easily access the Spring application context (and the EntityManager that is already managed by Spring) like so:

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应用程序上下文存储在该名称中:

Example of the Spring application context. Please note the value of the applicationContextSchedulerContextKey property that contains the name of the Quartz job application context property name into which the factory stores the Spring application context):

  <!--
    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,则可以使用以下方法实现相同的结果:

If you do not want to migrate your code to use the Spring SchedulerFactoryBean, you can achieve the same result with:

    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调度程序上下文中.

Alternatively, instead of storing the Spring application context in the Quartz scheduler context in your JobScheduler class, you can store the EntityManager instance there.

这篇关于在程序化管理的Quartz作业中注入Entity Manager的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆