views:

521

answers:

3

Hi guys,

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

+2  A: 

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
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
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
Could it be that the @Service("myService") and @Transactional annotations clash?
niklassaers
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
+1  A: 

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
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 <aop:config/> but it seems to me that that is still within only one transaction manager?
niklassaers
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
+1  A: 

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
toolkit
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