2015-06-09 3 views
3

Я хочу создать динамические задания с использованием кварца, весны и спящего режима. Пользователи взаимодействуют с веб-сервиса для создания рабочих мест этого класса: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: Я использую один компонент конфигурации (а не файлы 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

КРАТКОЕ РЕШЕНИЕ: Пусть весна сделает вашу работу через заводы.

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

Я использую компонент для составления графика работ. Поэтому сначала я ввожу фабрики в этот компонент.Затем, когда я хочу запланировать работу, я использую этот фрагмент

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

вы в контексте пружинной удалось, и вы пытаетесь получить доступ к EntityManager с @PersistentContext, который является javax.persistence аннотаций. Попробуйте autowiring EntityManagerFactory bean с @Autowire, который, я предполагаю, вы настроите его в spring-context.xml и используйте entityManagerFactory.createEntityManager(), чтобы предоставить вам управляемый менеджер Spring Spring, который будет завернут весной и будет в менеджере транзакций, который вы определяете

+0

Не уверен, что я поняли. Я обновил свой вопрос с помощью основных методов моего компонента конфигурации. Я предполагаю, что вы хотите добавить @Autowired аннотацию в моем DAO и добавить еще один компонент в моей конфигурации, который вводит entityManagerFactory.createEntityManager(). Я прав? – 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 как фасоль:

<!-- 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> 
Смежные вопросы