2015-06-09 94 views
3

我想使用Quartz,Spring和Hibernate創建動態作業。用戶與Web服務交互,以創建就業這一類的Spring + Hibernate + Quartz:Dynamic Job

public class StartJobSpring extends QuartzJobBean { 

    private String jobId; 
    private String jobType; 

    @Autowired 
    private NoaJobInstancesDAO njiDAO; 

    @Transactional 
    @Override 
    protected void executeInternal(JobExecutionContext context) 
      throws JobExecutionException { 

     JobKey key = context.getJobDetail().getKey(); 
     JobDataMap dataMap = context.getMergedJobDataMap(); 

     // some logic 
     njiDAO.create(instanceUUID, noaJob.getNoaJob(jobId), jobType); 
    } 
} 

NoaJobInstancesDAO是一個簡單的DAO類,這使得使用Hibernate的的EntityManager的:

@Repository 
public class NoaJobInstancesDAOHibImpl implements NoaJobInstancesDAO { 

    @PersistenceContext 
    private EntityManager entityManager; 

    @Override 
    @Transactional 
    public NoaJobInstanceJPA create(NoaJobInstanceJPA entity) { 
     entityManager.persist(entity); 
     return entity; 
    } 

    @Override 
    public void create(String instance_uuid, NoaJobJPA job, String job_type) { 
     NoaJobInstanceJPA entity = new NoaJobInstanceJPA(instance_uuid, job, 
       job_type, "CREATED", null, null, "", "N", "N"); 
     this.create(entity); 
    } 
} 

的問題是當這項工作發生時,拋出異常:

javax.persistence.TransactionRequiredException: No transactional EntityManager available 

我無法理解爲什麼! 我安排這樣的工作在經理

JobDetail job = newJob(StartJobSpring.class).withIdentity(//anId) 
       .setJobData(//aJobMap).build(); 
getScheduler().getObject().scheduleJob(job, trigger); 

其中調度連線到經理爲

@Autowired 
private ApplicationContext applicationContext; 

@Bean 
SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource, JpaTransactionManager transactionManager) { 

    SchedulerFactoryBean bean = new SchedulerFactoryBean(); 

    AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory(); 
    jobFactory.setApplicationContext(applicationContext); 
    bean.setJobFactory(jobFactory); 

    bean.setTransactionManager(transactionManager); 

    return bean; 
} 

類AutowiringSpringBeanJobFactory相同Autowiring

在我的視角中,調度程序的接線有問題。實際上,我不明白我如何檢索應用程序上下文。

EDIT1:應用程序上下文似乎正確實例化。問題不可能在那裏。

EDIT2:我正在使用一個配置bean(不是xml文件)。這裏的主要方法:

@Bean 
LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) { 
    LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean(); 
    entityManagerFactoryBean.setDataSource(dataSource); 
    entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); 
    entityManagerFactoryBean.setPackagesToScan("package"); 

    Properties jpaProperties = new Properties(); 
    jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.OracleDialect"); 
    jpaProperties.put("hibernate.show_sql", "false"); 
    jpaProperties.put("hibernate.hbm2ddl.auto", "update"); 

    entityManagerFactoryBean.setJpaProperties(jpaProperties); 

    return entityManagerFactoryBean; 
} 

@Bean 
JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { 
    JpaTransactionManager transactionManager = new JpaTransactionManager(); 
    transactionManager.setEntityManagerFactory(entityManagerFactory); 
    return transactionManager; 
} 

@Bean 
public NoaJobInstancesDAO noaJobInstancesDAO() { 
    NoaJobInstancesDAOHibImpl noaJobInstancesDAO = new NoaJobInstancesDAOHibImpl(); 
    return noaJobInstancesDAO; 
} 

回答

0

SHORT SOLUTION:讓春天讓你的工作通過工廠。

LONG SOLUTION:這裏的長描述。我已經通過導入XML配置文件修改了配置文件:

<bean name="complexJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> 
    <property name="jobClass" value="jobs.StartJob" /> 
    <property name="durability" value="true" /> 
</bean> 

<bean id="cronTrigger" 
     class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> 
    <property name="jobDetail" ref="complexJobDetail" /> 
    <property name="cronExpression" value="0/5 * * ? * SAT-SUN" /> 
</bean> 

這樣,你有一個彈簧廠產生的工作情況。現在,這裏是我更新的java配置類

@ImportResource({"spring-quartz-context.xml"}) 
public class BeanConfig { 
    //autowired from xml 
    @Autowired JobDetailFactoryBean jobDetailFactory; 
    @Autowired CronTriggerFactoryBean cronTriggerFactory; 

    @Bean 
    public SchedulerFactoryBean schedulerFactoryBean(LocalContainerEntityManagerFactoryBean entityManagerFactory) { 

     SchedulerFactoryBean bean = new SchedulerFactoryBean(); 
     bean.setApplicationContextSchedulerContextKey("applicationContext"); 

     bean.setSchedulerName("MyScheduler"); 

     //used for the wiring 
     Map<String, Object> schedulerContextAsMap = new HashMap<String, Object>(); 
     schedulerContextAsMap.put("noaJobDAO", noaJobDAO()); 
     schedulerContextAsMap.put("noaJobInstancesDAO", noaJobInstancesDAO()); 
     schedulerContextAsMap.put("esbClient", this.esbClient()); 
     bean.setSchedulerContextAsMap(schedulerContextAsMap); 

     bean.setQuartzProperties(quartzProperties()); 

     return bean; 
    } 

    @Bean 
    public Properties quartzProperties() { 
     PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean(); 
     propertiesFactoryBean.setLocation(new ClassPathResource("quartz.properties")); 
     Properties properties = null; 
     try { 
      propertiesFactoryBean.afterPropertiesSet(); 
      properties = propertiesFactoryBean.getObject(); 

     } catch (IOException e) { 
      log.warn("Cannot load quartz.properties."); 
     } 

     return properties; 
    } 

    // other beans (as included in the question) 
} 

我使用一個bean來安排作業。所以首先我在這個bean中注入工廠。然後,當我想安排一個工作,我用這個片段

JobDetail job = jobDetailFactory.getObject(); 
Trigger trigger = cronTriggerFactory.getObject(); 
scheduler.schedule(job, trigger); 

我還修改了作業類

@Service 
public class StartJob extends QuartzJobBean { 

    // the DAO 
    private NoaJobInstancesDAO njiDAO; 

    public void executeInternal(JobExecutionContext context) 
      throws JobExecutionException { 
     init(context.getJobDetail().getJobDataMap(), context.getScheduler() 
        .getContext()); 
     // some logic here 
     njiDAO.create(params); 
    } 

    private void init(JobDataMap jobContextMap, 
      SchedulerContext schedulerContext) { 
     // some initialization using the job data map, not interesting for DAOs 

     // row that inject the correct DAO 
     this.njiDAO = (NoaJobInstancesDAO) schedulerContext 
       .get("noaJobInstancesDAO"); 
    } 
} 

問題解決了!

0

你在彈簧管理背景和您嘗試訪問與@PersistentContext EntityManager的是一個javax.persistence註釋。嘗試使用@Autowire自動裝配EntityManagerFactory bean,我假設您在spring-context.xml中配置它,並使用entityManagerFactory.createEntityManager()爲您提供spring彈出的託管實體管理器,它將被spring包裝,並位於您定義的事務管理器中

+0

不確定我理解了。我用我的配置bean的主要方法更新了我的問題。我想你的意思是在我的DAO中添加@Autowired註釋,並在我的配置中添加另一個注入entityManagerFactory.createEntityManager()的bean。我對嗎? – dylaniato

+0

是在您的DAO層,而不是注入EntityManager,注入EntityManagerFactory與Autowired註釋,並在您的方法,從entityManagerFactory.createEntityManager() – AntJavaDev

+0

我會盡快嘗試獲取實體管理器。只是幾個問題。第一:我也在我的主線程中使用DAO。這種修改會影響我的正常流程嗎?第二:仍然可以使用createEntityManager()方法忽略事務管理? – dylaniato

0

我解決了這個問題,這樣做:

在作業(它是強制性獲得一個接口):

public class SchedulerJob extends QuartzJobBean { 
public void executeInternal(JobExecutionContext context) 
     throws JobExecutionException { 
    try{ 
     <YOUR_BEAN_DAO_INTERFACE_OBJECT> = ((ApplicationContext) context.getJobDetail().getJobDataMap().get("applicationContext")).get("<YOUR_BEAN_DAO_INTERFACE_ID>"); 
    } catch (Exception e){ 
     e.printStackTrace(); 
     return; 
    } 
} 

}

在應用程序的.XML方面: 還有必要在這個xml中聲明爲一個bean:

<!-- Spring Quartz Scheduler job --> 
<bean name="schedulerJob" class="org.springframework.scheduling.quartz.JobDetailBean"> 
    <property name="jobClass" value="<PATH_OF_YOUR_CLASS_JOB>.SchedulerJob" /> 
    <property name="applicationContextJobDataKey" value="applicationContext" /> 
</bean> 

<!-- Cron Trigger, run every 10 seconds --> 
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> 
    <property name="jobDetail" ref="schedulerJob" /> 
    <property name="cronExpression" value="0/10 * * * * ?" /> 
</bean> 

<!-- DI --> 
<bean id="scheduler" 
    class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> 
    <property name="jobDetails"> 
     <list> 
      <ref bean="schedulerJob" /> 
     </list> 
    </property> 

    <property name="triggers"> 
     <list> 
      <ref bean="cronTrigger" /> 
     </list> 
    </property> 
</bean>