Spring + Hibernate + Quartz:动态作业 [英] Spring + Hibernate + Quartz: Dynamic Job

查看:155
本文介绍了Spring + Hibernate + Quartz:动态作业的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用Quartz,Spring和Hibernate创建动态作业。用户与Web服务进行交互以创建此类的作业

  public class StartJobSpring extends QuartzJobBean { 

private String jobId;
private String jobType;

@Autowired
私人NoaJobInstancesDAO njiDAO;

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

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

//一些逻辑
njiDAO.create(instanceUUID,noaJob.getNoaJob(jobId),jobType);


NoaJobInstancesDAO 是一个简单的DAO类,它使用Hibernate的 EntityManager

  @Repository 
public class NoaJobInstancesDAOHibImpl实现NoaJobInstancesDAO {

@PersistenceContext
private EntityManager entityManager;

@Override
@Transactional
public NoaJobInstanceJPA create(NoaJobInstanceJPA entity){
entityManager.persist(entity);
返回实体;

$ b @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);




$ b $ p
$ b

问题是,当这个任务触发时,被抛出:

  javax.persistence.TransactionRequiredException:没有事务性的EntityManager可用

我无法理解为什么!
我以这种方式在经理课程中安排工作

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

其中调度程序连接到经理

  @Autowired 
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);

返回bean;
}

类AutowiringSpringBeanJobFactory与 Autowiring



在我的opion中,调度程序接线有问题。实际上,我不明白我如何检索应用程序上下文。



EDIT1:应用程序上下文似乎是正确实例化的。问题不在那里。



EDIT2:我使用了一个配置bean(不是xml文件)。这里的主要方法:

$ $ $ $ b $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource){
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource);
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
entityManagerFactoryBean.setPackagesToScan(package);

属性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);

返回entityManagerFactoryBean;


$ Be
JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
返回transactionManager;
}

@Bean
public NoaJobInstancesDAO noaJobInstancesDAO(){
NoaJobInstancesDAOHibImpl noaJobInstancesDAO = new NoaJobInstancesDAOHibImpl();
返回noaJobInstancesDAO;


解决方案

让Spring通过工厂开展工作。



LONG SOLUTION:这里有很长的描述。我通过导入一个xml配置文件修改了我的配置文件:

 < bean name =complexJobDetailclass =org。 springframework.scheduling.quartz.JobDetailFactoryBean> 
< property name =jobClassvalue =jobs.StartJob/>
< property name =durabilityvalue =true/>
< / bean>

< bean id =cronTrigger
class =org.springframework.scheduling.quartz.CronTriggerFactoryBean>
< property name =jobDetailref =complexJobDetail/>
< property name =cronExpressionvalue =0/5 * *?* SAT-SUN/>
< / bean>

这样,您就有了一个可以生成作业实例的弹簧工厂。现在,这里是我更新的java配置类。
$ b $ $ p $ @ImportResource({spring-quartz-context.xml})
public class BeanConfig {
// autowired from xml
@Autowired JobDetailFactoryBean jobDetailFactory;
@Autowired CronTriggerFactoryBean cronTriggerFactory;

@Bean
public Sc​​hedulerFactoryBean schedulerFactoryBean(LocalContainerEntityManagerFactoryBean entityManagerFactory){

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

bean.setSchedulerName(MyScheduler);

//用于接线
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());

返回bean;
}

@Bean
公共属性quartzProperties(){
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource(quartz.properties));
属性properties = null;
尝试{
propertiesFactoryBean.afterPropertiesSet();
properties = propertiesFactoryBean.getObject();

} catch(IOException e){
log.warn(无法加载quartz.properties。);
}

返回属性;
}

//其他bean(包含在问题中)
}

我使用bean来安排作业。所以首先我在这个bean中注入工厂。然后,当我想安排一个工作,我使用这段代码

  JobDetail job = jobDetailFactory.getObject(); 
触发器触发器= cronTriggerFactory.getObject();
scheduler.schedule(job,trigger);

我也修改了工作类

  @Service 
public class StartJob extends QuartzJobBean {

// DAO
private NoaJobInstancesDAO njiDAO;
$ b $ public void executeInternal(JobExecutionContext context)
throws JobExecutionException {
init(context.getJobDetail()。getJobDataMap(),context.getScheduler()
.getContext ));
//这里有一些逻辑
njiDAO.create(params);


private void init(JobDataMap jobContextMap,
SchedulerContext schedulerContext){
//使用作业数据映射进行一些初始化,对DAO不感兴趣

//注入正确DAO的行
this.njiDAO =(NoaJobInstancesDAO)schedulerContext
.get(noaJobInstancesDAO);


code


问题解决了!


I want to create dynamically jobs using Quartz, Spring and Hibernate. Users interact with a web service to create jobs of this class:

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

The NoaJobInstancesDAO is a simple DAO class which makes use of Hibernate's 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);
    } 
}

The problem is that when this job fires, an exception is thrown:

javax.persistence.TransactionRequiredException: No transactional EntityManager available

and i can't understand why! I schedule the job in this way in a Manager class

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

where the scheduler is wired to the manager as

@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;
}

The class AutowiringSpringBeanJobFactory is the same as Autowiring.

In my opion there's something wrong in the scheduler wiring. In fact, I don't understand how I can retrieve the application context.

EDIT1: The application context seems to be correctly instanced. The problem could not be there.

EDIT2: I'm using a single configuration bean (not xml files). Here the main methods:

@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;
}

解决方案

SHORT SOLUTION: let Spring make your jobs through factories.

LONG SOLUTION: here the long description. I have modified my configuration file by importing an xml configuration file:

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

This way, you have a spring factory which produces jobs instances. Now, here's my updated java config class

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

I use a bean to schedule jobs. So first I inject factories in this bean. Then when I want to schedule a Job, I use this snippet

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

I have also modified the job class

@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");
    }
}

Problem solved!

这篇关于Spring + Hibernate + Quartz:动态作业的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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