Results 1 to 7 of 7

Thread: custom callback before a transaction is committed

  1. #1
    Join Date
    Jun 2007
    Location
    Melbourne, Australia
    Posts
    14

    Default custom callback before a transaction is committed

    Hi,
    I'm using JTATransactionManager and JDK 5 annotations to manage transactions with hibernate, using Spring 2.0.5.

    I would like to be able to hook in some custom code just before the database commit is called. I could use the hibernate event listener framework, but that is called on updates to the individual POJO entities - I want my code to run just once towards the end of the transaction.

    As an added bit of complexity - my code must run within the transaction - i.e., it does some database work (via hibernate again) of its own.

    I attempted doing this with AOP, wiring an aspect around AbstractPlatformTransactionManager.commit(Transact ionStatus) but this resulted in a circular depency at spring startup around the hibernate session factory bean.

    Any ideas on how I can accomplish this?

    Thanks,
    Ishaaq

  2. #2
    Join Date
    Sep 2006
    Location
    UK
    Posts
    8,424

    Default

    I would have thought you were on the right track with AOP. Is it possible to see the problems you were having?
    Last edited by karldmoore; Aug 29th, 2007 at 11:56 AM.
    Barracuda Networks SSL VPN Lead Developer
    http://pramatr.wordpress.com
    http://twitter.com/karldmoore
    http://www.linkedin.com/in/karldmoore
    Any postings are my own opinion, and should not be attributed to my employer or clients.

  3. #3
    Join Date
    Jun 2006
    Location
    The Netherlands
    Posts
    13,625

    Default

    I agree with Karl AOP is the way to go. You could write an MethodInterceptor and make sure that that is executed after the TransactionInterceptor (make it Ordered and set the attribute lower then the Transaction order). That way it will be called after the start of your transaction and before the commit of the transaction.
    Marten Deinum
    Java Consultant / Pragmatist / Open Source Enthousiast / Author


    Pro Spring MVC: With Web Flow
    Conspect

    Have you read the reference guide.
    Use the [ code ] tags, young padawan

  4. #4
    Join Date
    Jun 2005
    Posts
    4,231

    Default

    If you are using Spring transaction manager (you don't say explicitly, but I assume you are), have you looked at TransactionSynchronization and TransactionSynchronizationManager? AOP can still be part of the solution if the concern is cross-cutting, but since the transaction synchronizations are thread local, you can set them up from anywhere inside a transaction.

  5. #5
    Join Date
    Jun 2007
    Location
    Melbourne, Australia
    Posts
    14

    Default

    Well, the transaction interceptor is a bit too early. Remember that I want to intercept just before the transaction is commited (or rolled back as the case may be). The transaction interceptor is fired multiple times in the life-cycle of a use-case as multiple services that have been marked as @Transactional are called within a single-use case.

    What I'd like to do is intercept at AbstractPlatformTransactionManager.commit(Transact ionStatus) (and the equivalent rollback method) so that my custom code is guaranteed to be called once and only once just before a database commit/rollback is accomplished.

    The problem I get when trying to intercept those two methods in the transaction manager is a bean creation exception when applying an aspect to the methods. This happens whether I use the @Aspect way or the older Spring 1.x AOP API.

    Here's the stack trace:

    Cannot resolve reference to bean 'transactionManager' while setting bean property 'transactionManager'; nested exception is org.springframework.beans.factory.BeanCurrentlyInC reationException: Error creating bean with name 'transactionManager': Bean with name 'transactionManager' has been injected into other beans [(inner bean)] in its raw version as part of a circular reference, but has eventually been wrapped (for example as part of auto-proxy creation). This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.
    Caused by: org.springframework.beans.factory.BeanCreationExce ption: Error creating bean with name 'transactionInterceptor' defined in URL [file:/Users/ishaaq/IdeaProjects/admomentum/admanager/config/admanager-appcontext-persistence.xml]: Cannot resolve reference to bean 'transactionManager' while setting bean property 'transactionManager'; nested exception is org.springframework.beans.factory.BeanCurrentlyInC reationException: Error creating bean with name 'transactionManager': Bean with name 'transactionManager' has been injected into other beans [(inner bean)] in its raw version as part of a circular reference, but has eventually been wrapped (for example as part of auto-proxy creation). This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.
    Caused by: org.springframework.beans.factory.BeanCurrentlyInC reationException: Error creating bean with name 'transactionManager': Bean with name 'transactionManager' has been injected into other beans [(inner bean)] in its raw version as part of a circular reference, but has eventually been wrapped (for example as part of auto-proxy creation). This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.
    at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.createBean(AbstractAuto wireCapableBeanFactory.java:432)
    at org.springframework.beans.factory.support.Abstract BeanFactory$1.getObject(AbstractBeanFactory.java:2 51)
    at org.springframework.beans.factory.support.DefaultS ingletonBeanRegistry.getSingleton(DefaultSingleton BeanRegistry.java:156)
    at org.springframework.beans.factory.support.Abstract BeanFactory.getBean(AbstractBeanFactory.java:248)
    at org.springframework.beans.factory.support.Abstract BeanFactory.getBean(AbstractBeanFactory.java:160)
    at org.springframework.beans.factory.support.BeanDefi nitionValueResolver.resolveReference(BeanDefinitio nValueResolver.java:261)
    at org.springframework.beans.factory.support.BeanDefi nitionValueResolver.resolveValueIfNecessary(BeanDe finitionValueResolver.java:109)
    at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.applyPropertyValues(Abs tractAutowireCapableBeanFactory.java:1100)
    at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.populateBean(AbstractAu towireCapableBeanFactory.java:862)
    at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.createBean(AbstractAuto wireCapableBeanFactory.java:424)
    at org.springframework.beans.factory.support.Abstract BeanFactory$1.getObject(AbstractBeanFactory.java:2 51)
    at org.springframework.beans.factory.support.DefaultS ingletonBeanRegistry.getSingleton(DefaultSingleton BeanRegistry.java:156)
    at org.springframework.beans.factory.support.Abstract BeanFactory.getBean(AbstractBeanFactory.java:248)
    at org.springframework.beans.factory.support.Abstract BeanFactory.getBean(AbstractBeanFactory.java:160)
    at org.springframework.beans.factory.support.BeanDefi nitionValueResolver.resolveReference(BeanDefinitio nValueResolver.java:261)
    at org.springframework.beans.factory.support.BeanDefi nitionValueResolver.resolveValueIfNecessary(BeanDe finitionValueResolver.java:109)
    at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.applyPropertyValues(Abs tractAutowireCapableBeanFactory.java:1100)
    at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.populateBean(AbstractAu towireCapableBeanFactory.java:862)
    at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.createBean(AbstractAuto wireCapableBeanFactory.java:424)
    at org.springframework.beans.factory.support.Abstract BeanFactory$1.getObject(AbstractBeanFactory.java:2 51)
    at org.springframework.beans.factory.support.DefaultS ingletonBeanRegistry.getSingleton(DefaultSingleton BeanRegistry.java:156)
    at org.springframework.beans.factory.support.Abstract BeanFactory.getBean(AbstractBeanFactory.java:248)
    at org.springframework.beans.factory.support.Abstract BeanFactory.getBean(AbstractBeanFactory.java:160)
    at org.springframework.aop.framework.autoproxy.BeanFa ctoryAdvisorRetrievalHelper.findAdvisorBeans(BeanF actoryAdvisorRetrievalHelper.java:87)
    at org.springframework.aop.framework.autoproxy.Abstra ctAdvisorAutoProxyCreator.findCandidateAdvisors(Ab stractAdvisorAutoProxyCreator.java:96)
    at org.springframework.aop.framework.autoproxy.Abstra ctAdvisorAutoProxyCreator.findEligibleAdvisors(Abs tractAdvisorAutoProxyCreator.java:83)
    at org.springframework.aop.framework.autoproxy.Abstra ctAdvisorAutoProxyCreator.getAdvicesAndAdvisorsFor Bean(AbstractAdvisorAutoProxyCreator.java:66)
    at org.springframework.aop.framework.autoproxy.Abstra ctAutoProxyCreator.postProcessAfterInitialization( AbstractAutoProxyCreator.java:296)
    at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.applyBeanPostProcessors AfterInitialization(AbstractAutowireCapableBeanFac tory.java:315)
    at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.initializeBean(Abstract AutowireCapableBeanFactory.java:1181)
    at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.createBean(AbstractAuto wireCapableBeanFactory.java:428)
    at org.springframework.beans.factory.support.Abstract BeanFactory$1.getObject(AbstractBeanFactory.java:2 51)
    at org.springframework.beans.factory.support.DefaultS ingletonBeanRegistry.getSingleton(DefaultSingleton BeanRegistry.java:156)
    at org.springframework.beans.factory.support.Abstract BeanFactory.getBean(AbstractBeanFactory.java:248)
    at org.springframework.beans.factory.support.Abstract BeanFactory.getBean(AbstractBeanFactory.java:160)
    at org.springframework.context.support.AbstractApplic ationContext.getBean(AbstractApplicationContext.ja va:733)
    at org.springframework.context.support.AbstractApplic ationContext.registerBeanPostProcessors(AbstractAp plicationContext.java:511)
    at org.springframework.context.support.AbstractApplic ationContext.refresh(AbstractApplicationContext.ja va:337)
    at org.springframework.test.AbstractSingleSpringConte xtTests.createApplicationContext(AbstractSingleSpr ingContextTests.java:199)
    at org.springframework.test.AbstractSingleSpringConte xtTests.loadContextLocations(AbstractSingleSpringC ontextTests.java:179)
    at org.springframework.test.AbstractSingleSpringConte xtTests.loadContext(AbstractSingleSpringContextTes ts.java:158)
    at org.springframework.test.AbstractSpringContextTest s.getContext(AbstractSpringContextTests.java:105)
    at org.springframework.test.AbstractSingleSpringConte xtTests.setUp(AbstractSingleSpringContextTests.jav a:87)
    at org.springframework.test.ConditionalTestCase.runBa re(ConditionalTestCase.java:69)
    at com.intellij.rt.execution.junit.JUnitStarter.main( JUnitStarter.java:40)

  6. #6
    Join Date
    Jun 2007
    Location
    Melbourne, Australia
    Posts
    14

    Default

    In reply to your question Dave - I am using Spring-based transaction management. Specifically, the JtaTransactionManager.

    I did see references to TransactionSynchronizationManager in the source code for AbstractPlatformTransactionManager and the thought did cross my mind that that would be a great place to put my code but I don't know how to set it up. I have a feeling I should be using TransactionSynchronizationManager.registerSynchron ization() but have no idea at what point I should do this. The documentation is silent on this (or I couldn't find anything). Any pointers?

    Thanks,
    Ishaaq

  7. #7
    Join Date
    Jun 2007
    Location
    Melbourne, Australia
    Posts
    14

    Default

    Aha! I think I know now why I am getting the BeanCreationException problem. Found this in my log messages:

    2007-06-27 18:28:20,687 INFO [main] context.support.AbstractApplicationContext$BeanPos tProcessorChecker (AbstractApplicationContext.java:1006) - Bean 'transactionManager' is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)


    On reading the spring documentation I found (note 2 in section 3.7.1) that since I'm using the @Transactional annotations that are using AOP anyway, the dependent transactionManager bean in not eligible for auto-proxying. So, I can't use AOP for what I want to do. Aaargh!

    Ok, so now the only possibility I have is Dave's suggestion of using the TransactionSynchronizationManager.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •