/ / Não é possível usar a classe Repository de spring data jpa em um método de classe no Quartz por quê? - spring, quartz-scheduler, spring-data-jpa

Não é possível usar a classe Repository da jpa de dados de primavera em um método de classe no Quartz por que? - spring, quartz-scheduler, spring-data-jpa

Eu estou desenvolvendo multiple-jobs-in-quartz-spring-example que é uma combinação de Spring + Quartz + Spring Data JPA. Estou procurando desenvolver um código que será executado em 5 segundos, chegará ao banco de dados e buscará um registro do banco de dados. Estou quase perto de fazê-lo funcionar, mas vejo um pequeno problema. Em meu JobA.class, não obtenho uma instância de CustomerRepository.java por quê? É sempre nulo e é por isso que o código não consegue acessar o banco de dados. Por favor, guie como resolver este problema?

Código-fonte em: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");
}
}

insira a descrição da imagem aqui

Respostas:

0 para resposta № 1

Acessando o seguinte link http://codrspace.com/Khovansa/spring-quartz-with-a-database/ deve ajudar.

Citando o link acima,

Quartz cria uma nova instância de trabalho em cadainvocação. Isso significa que os jobs do Quartz não são beans regulares do Spring e não podemos esperar que a mágica do Spring tenha efeito automaticamente (e o "JobDetailFactoryBean" do Spring não é inteligente o suficiente para fazer isso por nós). Portanto, teremos que implementar nossa própria fábrica de empregos que sobrescreverá a SpringBeanJobFactory padrão.

Então você precisa ter um custom SpringBeanJobFactory de extending SpringBeanJobFactory & implementing ApplicationContextAware e finalmente invocar beanFactory.autowireBean(job)


0 para resposta № 2

Vamos abrir a discussão aqui agora. E espere a orientação / ajuda de todos os especialistas aqui.

No exemplo acima, eu modifiquei JobA.java classe para obter uma instância do repositório CustomerRepository usando injeção de construtor como abaixo:

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

Mas o problema é que, quando usamos a instância customerRepository no método executeInternal (), ela a anula por quê? Por quê ? Se de alguma forma a instância não for anulada, terminamos !!!!