无法在Quartz中的类方法上使用Spring数据jpa的Repository类为什么?

时间:2016-09-03 09:04:17

标签: spring quartz-scheduler spring-data-jpa

我正在开发multiple-jobs-in-quartz-spring-example,它是Spring + Quartz + Spring Data JPA的组合。我正在寻找一个将在5秒内运行的代码,它将命中DB并从DB获取记录。我几乎接近使它工作,但我看到小问题。 在我的JobA.class中,我没有得到CustomerRepository.java的实例为什么?它总是为空,这就是为什么代码无法访问数据库。请指导如何解决这个问题?

源代码: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>

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

enter image description here

2 个答案:

答案 0 :(得分:1)

让我们现在开始讨论。并希望所有专家在这里提供指导/帮助。

在上面的示例中,我修改了JobA.java类以使用Constructor注入获取CustomerRepository存储库实例的实例,如下所示:

@Service
public class JobA extends QuartzJobBean {

    private CustomerRepository customerRepository = null;

    @Autowired
    public JobA(CustomerRepository customerRepository) {
        this.customerRepository = customerRepository;
        getCustomerList();
    }
    public JobA() { }

    @Override
    protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
        System.out.println("~~~~~~~ Job A is runing ~~~~~~~~");
    }

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

但问题是,当我们在executeInternal()方法中使用customerRepository实例时,它会使其无效?为什么?如果不知何故实例不会无效我们就完成了!!!!

答案 1 :(得分:0)

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

从上述链接引用,

  

Quartz在每次调用时创建一个新的作业实例。这意味着Quartz作业不是常规的Spring bean,我们不能指望Spring魔法能够自动生效(并且Spring&#39; JobDetailFactoryBean&#39;对我们来说不够聪明)。因此,我们必须实现我们自己的作业工厂,它将覆盖默认的SpringBeanJobFactory。

因此,您需要custom SpringBeanJobFactory extending SpringBeanJobFactory & implementing ApplicationContextAware,最后调用beanFactory.autowireBean(job)