Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AnnotationTransactionAspect retains reference to closed BeanFactory [SPR-7964] #12619

Closed
spring-issuemaster opened this issue Feb 15, 2011 · 4 comments

Comments

Projects
None yet
2 participants
@spring-issuemaster
Copy link
Collaborator

commented Feb 15, 2011

Andy Wilkinson opened SPR-7964 and commented

We have a perhaps unusual situation where we have a mixture of plain JUnit tests and Spring-powered JUnit tests (annotated to run with SpringJUnit4ClassRunner) in the same project. All of the Spring-powered tests are annotated with @DirtiesContext. The project's compiled with AspectJ and is using Spring's AspectJ-powered transaction support. There are three test classes involved, and a failure occurs if they run in a particular order. In the order:

  1. Not Spring-powered
  2. Spring-powered
  3. Spring-powered

all of the tests will pass.

In the order:

  1. Spring-powered
  2. Not Spring-powered
  3. Spring-powered

the tests will fail.

In the failing case, the test that is not Spring-powered performs some entirely unexpected application context initialization. As this test isn't being run with Spring's runner and isn't annotated with @DirtiesContext, this leaves the application context in an unexpected state which causes the second class of Spring-powered tests to fail.

Crucially, the tests that aren't Spring-powered call a method that is annotated with @Transactional and has therefore been woven with Spring's transaction aspects. When this method is driven, the before advice results in determineTransactionManager() being called on AnnotationTransactionAspect. Unexpectedly AnnotationTransactionAspect has a non-null beanFactory reference so it asks the bean for the transaction manager. It's at this point that the unexpected initialization occurs.

To get to the point (finally!), I believe that the problem is that AnnotationTransactionAspect is being left with a reference to an out-of-date BeanFactory instance. My guess is that setting this reference to null during the cleanup processing triggered by the presence of the @DirtiesContext annotation will fix the problem.

I'm currently working around the failure with the following in the test class that's not Spring-powered:

@BeforeClass
public static void removeBeanFactoryFromAnnotationTransactionAspect() {
    AnnotationTransactionAspect.aspectOf().setBeanFactory(null);
}

Further Resources


Affects: 3.0.5

Issue Links:

  • #11019 TestContext framework should support one AspectJ instance per ApplicationContext
  • #17123 AnnotationTransactionAspect retains reference to JpaTransactionManager from closed context

1 votes, 4 watchers

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Aug 10, 2013

Sam Brannen commented

This is related to #11019 and #17123.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Oct 3, 2014

Ludovic Praud commented

This one make me lose 3h to understand and to find a workaround.

I use @Transactional annotation with Spring data JPA and play framework 2.3.4. Play has a mechanism to recompile and reload classes when they are modified. The spring context is closed then reloaded BUT the AnnotationTransactionAspect keep a reference of the previous JpaTransactionManager which uses a CLOSED JPA SessionFactory, thus throwing a CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is java.lang.IllegalStateException: EntityManagerFactory is closed.

To fix this, may be it should be possible to make org.springframework.transaction.interceptor.TransactionAspectSupport implements org.springframework.beans.factory.DisposableBean and unload JpaTransactionManager?

The work around was to do on applicationContext.close() :

AnnotationTransactionAspect.aspectOf().setTransactionManager(null);
AnnotationTransactionAspect.aspectOf().setTransactionManagerBeanName(null);

then do on applicationContext.refresh() :

AnnotationTransactionAspect.aspectOf().setBeanFactory(applicationContext);
@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Dec 8, 2014

Sam Brannen commented

Ludovic Praud, the behavior you experienced is likely a direct result of the caching introduced in #16570.

See also: #17123

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Apr 20, 2015

Stéphane Nicoll commented

This is finally addressed in ca91956b

It looks very similar to what was necessary in #17123

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.