首页 文章

Spring Hibernate Quartz:动态作业

提问于
浏览
3

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

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

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

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

3 回答

  • 0

    您处于Spring托管上下文中,并尝试使用@PersistentContext访问EntityManager,这是一个javax.persistence注释 . 尝试使用@Autowire自动装配EntityManagerFactory bean,我假设您在spring-context.xml中配置它,并使用entityManagerFactory.createEntityManager()为您提供Spring管理实体管理器,该管理器将由spring包装并位于您定义的事务管理器中

  • 0

    SHORT SOLUTION: 让 Spring 天通过工厂做你的工作 .

    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>
    

    这样,您就有了一个生成作业实例的 spring 工厂 . 现在,这是我更新的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中注入工厂 . 然后当我想安排一个Job时,我会使用这个片段

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

    Problem solved!

  • 0

    我这样解决了这个问题:

    在Job中(必须获得一个接口):

    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>
    

相关问题