为什么无法在 Quartz 的类方法上使用 Spring Data jpa 的 Repository 类? [英] Unable to use Repository class of spring data jpa on a class method in Quartz why?

查看:54
本文介绍了为什么无法在 Quartz 的类方法上使用 Spring Data jpa 的 Repository 类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发 multiple-jobs-in-quartz-spring-example,它是 Spring + Quartz + Spring Data JPA 的组合.我正在寻求开发一个将在 5 秒内运行的代码,它将命中 DB 并从 DB 中获取记录.

我快要让它工作了,但我发现了一个小问题.在我的 JobA.class 中,为什么我没有得到 CustomerRepository.java 的实例?它始终为空,这就是代码无法命中 DB 的原因.

源代码位于:

解决方案

通过以下链接 http://codrspace.com/Khovansa/spring-quartz-with-a-database/ 应该会有所帮助.

引用上面的链接,

<块引用>

Quartz 在每次调用时都会创建一个新的作业实例.这意味着 Quartz 作业不是常规的 Spring bean,我们不能指望 Spring 魔法会自动生效(并且 Spring 的JobDetailFactoryBean"不够聪明,无法为我们做到这一点).所以我们必须实现我们自己的作业工厂来覆盖默认的 SpringBeanJobFactory.

所以你需要通过 extending SpringBeanJobFactory & 来拥有一个 custom SpringBeanJobFactory实现 ApplicationContextAware 并最终调用 beanFactory.autowireBean(job)

I'm developing multiple-jobs-in-quartz-spring-example which is combination of Spring + Quartz + Spring Data JPA. I'm looking to developed a code which will run in 5 sec, it will hit to DB and fetches a records from DB.

I am close to making it working but I see small problem. In my JobA.class, why don't I get an instance of CustomerRepository.java? It's always null and thats why code unable to hit to DB.

Source code at: http://www.github.com/test512/multiple-jobs-in-quartz-spring-example.gi‌​t.

JobA.java

@Service
public class JobA extends QuartzJobBean {

    private CustomerRepository customerRepository = null;
    
    @Autowired
    public JobA(CustomerRepository customerRepository) {
        this.customerRepository = customerRepository;
    }
    public JobA() { }
    
    @Override
    protected void executeInternal(JobExecutionContext executionContext) throws JobExecutionException {
        System.out.println("~~~~~~~ Job A is runing ~~~~~~~~");
        Trigger trigger = executionContext.getTrigger();
        System.out.println(trigger.getPreviousFireTime());
        System.out.println(trigger.getNextFireTime());
        getCustomerList();
    }
    
    private List<Customer> getCustomerList(){
        List<Customer> customers = customerRepository.findAll();
        for (Customer customer : customers) {
            System.out.println("------------------------------");
            System.out.println("ID : "+customer.getId());
            System.out.println("NAME : "+customer.getName());
            System.out.println("STATUS : "+customer.getStatus());
        }
        return customers;
    }
}

Customer.java

@Entity
@Table(name="customer")
public class Customer {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="ID")
    private Long id;
    
    @Column(name="NAME")
    private String name;
    
    @Column(name="STATUS")
    private String status;
    
    
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getStatus() {
        return status;
    }
    public void setStatus(String status) {
        this.status = status;
    }
}

CustomerRepository.java

public interface CustomerRepository extends JpaRepository<Customer, Long>{

}

dataSourceContext.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
        
    <context:property-placeholder location="classpath:database.properties"/>
    
    <!-- <jdbc:initialize-database data-source="dataSource" enabled="true">
        <jdbc:script location="classpath:db-schema.sql" />
        <jdbc:script location="classpath:db-test-data.sql" />
    </jdbc:initialize-database> -->
    
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${mysql.driver.class.name}" />
        <property name="url" value="${mysql.url}" />
        <property name="username" value="${mysql.username}" />
        <property name="password" value="${mysql.username}" />
    </bean>
    
    <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="showSql" value="true"/>
        <property name="generateDdl" value="true"/>
        <property name="database" value="MYSQL"/>
    </bean>
    
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
        <!-- spring based scanning for entity classes-->
        <property name="packagesToScan" value="com.mkyong.*"/>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"/>
</beans>

Spring-Quartz.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xmlns:repository="http://www.springframework.org/schema/data/repository"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
        http://www.springframework.org/schema/data/repository http://www.springframework.org/schema/data/repository/spring-repository.xsd">

    <import resource="classpath:dataSourceContext.xml"/>
    
    <jpa:repositories base-package="com.mkyong.repository" />
    <context:component-scan base-package="com.mkyong.*" />
    <context:annotation-config />

    <bean id="jobA" class="com.mkyong.job.JobA" />
    <bean id="jobB" class="com.mkyong.job.JobB" />
    <bean id="jobC" class="com.mkyong.job.JobC" />
    <bean id="autowiredA" class="com.mkyong.job.JobASpringBeanJobFactory" />

    <!-- ~~~~~~~~~ Quartz Job ~~~~~~~~~~ -->
    <bean name="JobA" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="jobClass" value="com.mkyong.job.JobA" />
    </bean>

    <bean name="JobB" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="jobClass" value="com.mkyong.job.JobB" />
    </bean>
    
    <bean name="JobC" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="jobClass" value="com.mkyong.job.JobC" />
    </bean>
    
    <!-- ~~~~~~~~~~~ Cron Trigger, run every 5 seconds ~~~~~~~~~~~~~ -->
    <bean id="cronTriggerJobA" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="JobA" />
        <property name="cronExpression" value="0/5 * * * * ?" />
    </bean>
    
    <bean id="cronTriggerJobB" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="JobB" />
        <property name="cronExpression" value="0/5 * * * * ?" />
    </bean>
    
    <bean id="cronTriggerJobC" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="JobC" />
        <property name="cronExpression" value="0/5 * * * * ?" />
    </bean>

    <!-- ~~~~~~~~~~~~~~~~  Scheduler bean Factory   ~~~~~~~~~~~~~~~~ -->
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="jobFactory" ref="autowiredA"/> 
        <property name="triggers">
            <list>
                <ref bean="cronTriggerJobA" />
                <!-- <ref bean="cronTriggerJobB" />
                <ref bean="cronTriggerJobC" /> -->
            </list>
        </property>
    </bean>
</beans>

JobASpringBeanJobFactory.java

public class JobASpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {

    private transient AutowireCapableBeanFactory beanFactory;

    @Override
    public void setApplicationContext(final ApplicationContext context) {
        beanFactory = context.getAutowireCapableBeanFactory();
    }

    @Override
    protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
        final Object job = super.createJobInstance(bundle);
        beanFactory.autowireBean(job);
        return job;
    }
}

App.java

public class App {
    public static void main(String[] args) throws Exception {
        ApplicationContext context = new ClassPathXmlApplicationContext("Spring-Quartz.xml");
    }
}

解决方案

Going through the following link http://codrspace.com/Khovansa/spring-quartz-with-a-database/ should help.

Quoting from the above link,

Quartz creates a new job instance on each invocation. It means that Quartz jobs are not regular Spring beans and we can't expect the Spring magic to take an effect automatically (and Spring's 'JobDetailFactoryBean' is not smart enough to do it for us). So we'll have to implement our own job factory that would overwrite the default SpringBeanJobFactory.

So you need to have a custom SpringBeanJobFactory by extending SpringBeanJobFactory & implementing ApplicationContextAware and finally invoke beanFactory.autowireBean(job)

这篇关于为什么无法在 Quartz 的类方法上使用 Spring Data jpa 的 Repository 类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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