2013-07-24 6 views
6

Pracuję nad aplikacją, która używa Spring 3, Hibernate i JPA. Mam dwie klasy w następujący sposób:Spring Scheduler - Jeśli istnieje cykliczna zależność, zaplanowana metoda nie rozpoczyna się w transakcji

@Component 
class Manager { 
    @Autowired 
    Util util; 
} 

i

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

Odpowiedni fragment z kontekstu aplikacji jest następująca:

<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"/> 

Przy tej konfiguracji, pojawia się następujący wyjątek

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) 

Jeśli usuniemy autowiring klasy Managera z klasy Util, to działa dobrze. Ponadto podczas debugowania wykryłem, że zaplanowana metoda rozpoczyna wykonywanie, nawet jeśli wystąpił błąd w pliku kontekstowym aplikacji.

Dla niektórych starszych powodów nie mogę uniknąć cyklicznej zależności. Czy ktoś może pomóc, dlaczego ten wyjątek występuje w przypadku cyklicznej zależności?

+0

Wydaje się, że zaplanowane procesy postprocesora gołe fasoli nawet gdyby to miało wystrzelić po twórcy proxy AOP (ponieważ postprocesory są sortowane). Myślę, że możesz wysłać błąd do Spring JIRA, przynajmniej takie zachowanie jest słabo udokumentowane. Aby obejść ten problem, można wywołać metodę transakcyjną z oddzielnego komponentu bean za pomocą zaplanowanej metody lub zamiast niego użyć transakcji TransactionTemplate. –

Odpowiedz

0

Można achive to za pomocą @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 
    } 
} 
Powiązane problemy