2

I read about using

  <context:component-scan base-package="tld.mydomain.business">
      <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
  </context:component-scan>

and annotate my service beans with @Service("myService"), and thought great, I'll do that, since I'm already doing that with my controllers. My usual service bean configuration looks like

  <bean id="userService" parent="txProxyTemplate">
    <property name="target">
      <bean class="tld.mydomain.business.UserServiceImpl"/>
    </property>
    <property name="proxyInterfaces" value="tld.mydomain.business.UserService"/>
  </bean>

so now that I generate them, how do I wrap them in a Hibernate proxy such as TransactionProxyFactoryBean? Or is there a better way to do that as well?

I have not yet gone all the way and used @Repository as well, is that required?

Cheers

Nik

niklassaers
  • 8,480
  • 20
  • 99
  • 146

3 Answers3

4

Using TransactionProxyFactoryBean is not encouraged in modern Spring applications, although it still works. The typical approach nowadays is to annotate classes with @Transactional, and then stick this element in your application context file:

<tx:annotation-driven transaction-manager="txManager"/>

This and other strategies are discussed in great depth in the reference document, and there's even a side note about TransactionProxyFactoryBean.

Rob H
  • 14,502
  • 8
  • 42
  • 45
  • Thanks a bunch, I had followed a book on Spring 2 that recommended the TransactionProxyFactoryBean, I see now I should have checked out the documentation more carefully. Just a quick follow-up, though: this seems to be only for the scenario where there is only a single transaction manager. I, unfortunately, have two as I need to work with two different databases. This was no problem using TransactionProxyFactoryBean. Table 9.2 and 9.3 don't seem to suggest I can – niklassaers Oct 27 '09 at 19:41
  • Hmm, when I do that, I get the following exception when accessing my services: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'org.springframework.transaction.interceptor.TransactionInterceptor#0' must be of type [org.aopalliance.aop.Advice], but was actually of type [org.springframework.transaction.interceptor.TransactionInterceptor] – niklassaers Oct 27 '09 at 20:10
  • Could it be that the @Service("myService") and @Transactional annotations clash? – niklassaers Oct 27 '09 at 20:37
  • After having spent hours on this bug I decided it was better to post the question as a separate question than a follow-up in this thread. Here's the link: http://stackoverflow.com/questions/1636063/transactional-services-beannotofrequiredtypeexception-should-be-advice-but-i – niklassaers Oct 28 '09 at 09:24
1

There's no need for

<context:include-filter type="annotation"expression="org.springframework.stereotype.Service"/>

Spring will register @Service, @Repository, @Component... once they are found in the base package.

Like @Rob said either use @Transactional or <aop:config>...</aop:config> to handle your transactions at the service level.

non sequitor
  • 18,296
  • 9
  • 45
  • 64
  • Thanks for the tip, I've removed the extra clutter. Do you have any suggestions to why I get the BeanNotOfRequiredTypeException above creeps in? Or how to deal with more than one transaction manager? I see from the doc that I can give different advice using but it seems to me that that is still within only one transaction manager? – niklassaers Oct 27 '09 at 20:28
  • Usually `BeanNotOfRequiredType` when you are injecting a bean of the wrong type but I can't speak further unless you post the stacktrace. Well you only need 1 `PlatformTransactionManager`, there's no need for 2 unless you have 2 diff `DataSource`. – non sequitor Oct 29 '09 at 15:50
1

If you have two different resources that need to be in the same transaction, then you will need to use JTA. See my answer to an earlier question here. Your config would need to look something like:

<tx:annotation-driven transaction-manager="txManager"/>

<bean id="txManager" 
    class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManagerName" value="appserver/jndi/path" />
</bean>

Where appserver/jndi/path would need to be replaced with the JNDI path of the JTA transaction manager that comes with your application server (although you can use a standalone JTA transaction manager such as JOTM as well). Typical paths as mentioned in the 2.5.x API are:

  • "java:comp/UserTransaction" for Resin 2.x, Oracle OC4J (Orion), JOnAS (JOTM), BEA WebLogic
  • "java:comp/TransactionManager" for Resin 3.x
  • "java:appserver/TransactionManager" for GlassFish
  • "java:pm/TransactionManager" for Borland Enterprise Server and Sun Application Server (Sun ONE 7 and later)
  • "java:/TransactionManager" for JBoss Application Server
Community
  • 1
  • 1
toolkit
  • 49,809
  • 17
  • 109
  • 135
  • Hi Toolkit, thanks a lot for your input. I've been able to get around it when I used TransactionProxyFactoryBean in that it's not strictly necessary to keep them in the same transaction, I can also have two, one of them is read-only. That's why I asked about saying what transaction goes where. Combining them both into one seems like the best idea. But both are JDBC connections, I haven't been using JNDI. But I'll read up on your suggestion in the morning (it's midnight over here now) Cheers -Nik – niklassaers Oct 27 '09 at 23:21