2013-07-24 17 views
6

Sto lavorando a un'applicazione che utilizza Spring 3, Hibernate e JPA. Ho due classi come segue:Spring Scheduler - Quando esiste una dipendenza ciclica, il metodo programmato non viene avviato nella transazione

@Component 
class Manager { 
    @Autowired 
    Util util; 
} 

e

@Component 
class Util { 
    @Autowired 
    Manager manager; 

    @Scheduled(fixedDelay = 1 * 60 * 1000) 
    @Transactional(propagation = Propagation.REQUIRED) 
    public void scheduledMethod(){ 
     // Need to update the database in a transaction 
    } 
} 

La parte rilevante dal contesto di applicazione è la seguente:

<context:component-scan base-package="packageName" /> 
    <tx:annotation-driven /> 
    <bean id="entityManagerFactory" 
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
     <property name="persistenceUnitName" value="defaultPU" /> 
     <property name="dataSource" ref="dataSource" /> 
    </bean> 
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
     <property name="entityManagerFactory" ref="entityManagerFactory" /> 
    </bean> 
    <task:annotation-driven executor="executor" scheduler="scheduler"/> 
    <task:executor id="executor" 
     pool-size="10" 
     queue-capacity="10000" 
     rejection-policy="CALLER_RUNS"/> 
    <task:scheduler id="scheduler" pool-size="10"/> 

Con questa configurazione, ottengo la seguente eccezione

javax.persistence.TransactionRequiredException: no transaction is in progress 
     at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:978) 
     at sun.reflect.GeneratedMethodAccessor88.invoke(Unknown Source) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
     at java.lang.reflect.Method.invoke(Method.java:601) 
     at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365) 
     at com.sun.proxy.$Proxy43.flush(Unknown Source) 
     at sun.reflect.GeneratedMethodAccessor88.invoke(Unknown Source) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
     at java.lang.reflect.Method.invoke(Method.java:601) 
     at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240) 
     at com.sun.proxy.$Proxy43.flush(Unknown Source) 

Se rimuovo l'autowiring della classe Manager dalla classe Util, funziona correttamente. Inoltre, durante il debug ho scoperto che il metodo pianificato inizia l'esecuzione anche se c'è qualche errore nel file di contesto dell'applicazione.

Per alcune ragioni ereditarie, non posso evitare la dipendenza ciclica. Qualcuno può aiutare perché questa eccezione si verifica in caso di dipendenza ciclica?

+0

sembra che i processi di Post-processor in programma di fagioli a nudo, anche se si suppone che il fuoco dopo AOP procura creatore (perché postprocessori sono ordinate). Penso che puoi inviare un bug a Spring JIRA, almeno questo comportamento è scarsamente documentato. Come soluzione alternativa, è possibile attivare il metodo transazionale da un bean separato con un metodo pianificato o utilizzare TransactionTemplate invece se transazionale. –

risposta

0

È possibile raggiungere questo obiettivo utilizzando @PostConstruct

@Component 
class Manager { 

    Util util; 

    public void setUtil(Util util) { 
     this.util = util; 
    } 
} 


@Component 
class Util { 
    @Autowired 
    Manager manager; 

    @PostConstruct 
    public void init(){ 
     manager.setUtil(this); 

    } 

    @Scheduled(fixedDelay = 1 * 60 * 1000) 
    @Transactional(propagation = Propagation.REQUIRED) 
    public void scheduledMethod(){ 
     // Need to update the database in a transaction 
    } 
}