简体   繁体   中英

Why does adding @Transactional causes exception org.springframework.beans.factory.BeanCreationException: Error creating bean with name?

I am learning Spring with Hibernate and I am playing a bit with my configuration to fully understand how it works. An answer to this will be quite helpful to understand what is going on. I have quite a perplexity about adding @Transactional to my @Repository object. When I add it I get the error:

WARNING: Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'soccerController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.edu.spring.soccer.service.AccountService com.edu.spring.soccer.controller.SoccerController.accountService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'accountService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.edu.spring.soccer.dao.AccountDaoImpl com.edu.spring.soccer.service.AccountService.accountDaoImpl; nested exception is java.lang.IllegalArgumentException: Can not set com.edu.spring.soccer.dao.AccountDaoImpl field com.edu.spring.soccer.service.AccountService.accountDaoImpl to com.sun.proxy.$Proxy63
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:298)

However when I delete the @Transactional everything works properly. I have read in several places that @Repository should be followed by @Transactional .

Following you see my configuration. This is the @Repository object with @Transactional . Note that extends an AbstractDao class that contains SessionFactory object.

@Repository
@Transactional //It causes the exception, without it, it works.
public class AccountDaoImpl extends AbstractDao implements AccountDao {

    public void saveAccount(Account account, String password) {
        //Both methods come from AbstractDao
        persist(account); 
        insertPassword(account, password); 
    }

}

However when I delete the @Transactional everything works properly. I have read in several places that @Repository should be followed by @Transactional .

Following you see my configuration:

beans-data.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:jee="http://www.springframework.org/schema/jee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
 http://www.springframework.org/schema/jee
 http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context.xsd
 http://www.springframework.org/schema/tx  
 http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <context:property-placeholder location="/WEB-INF/spring/environment.properties" />

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close" p:driverClassName="${dataSource.driverClassName}"
        p:url="${dataSource.url}" p:username="${dataSource.username}"
        p:password="${dataSource.password}" />

<!-- Taken from http://websystique.com/spring/spring4-hibernate4-mysql-maven-integration-example-using-annotations/ -->


    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan">
            <list>
                <value>com.edu.spring.soccer.domain</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql:false}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql:false}</prop>
            </props>
        </property>
    </bean>

   <bean id="transactionManager"  
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <tx:annotation-driven />
    <context:component-scan base-package="com.edu.spring.soccer.dao" />


</beans>

dispatcher-servlet.xml

I am doing the component-scan to all my packages and adding annotation-driven.

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/tx  
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <tx:annotation-driven />

    <context:component-scan base-package="com.edu.spring.soccer.controller" />
    <context:component-scan base-package="com.edu.spring.soccer.dao" />
    <context:component-scan base-package="com.edu.spring.soccer.domain" />
    <context:component-scan base-package="com.edu.spring.soccer.service" />

    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix">
            <value>/WEB-INF/views/jsp/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>

    <mvc:resources mapping="/resources/**" location="/resources/" />

    <mvc:annotation-driven />

    <bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
        p:basename="classpath:/messages" />

</beans>

Is it maybe related to having the component-scan and <tx:annotation-driven /> in the dispatcher-servlet.xml and then adding again @Transactional?. Maybe this causes some kind of redundancy.

The exception stack says it all :

nested exception is java.lang.IllegalArgumentException: Can not set com.edu.spring.soccer.dao.AccountDaoImpl field com.edu.spring.soccer.service.AccountService.accountDaoImpl to com.sun.proxy.$Proxy63

you are trying here to autowire AccountDaoImpl in your AccountService

But

AccountDaoImpl has that @Transactionnal annotation, so Spring has "proxied" it... You should autowire not the implementation but the interface , that is to say, in your AccountService change:

private AccountDaoImpl accountDaoImpl;

to

private AccountDao accountDao;

I believe it is not because of tx:annotation-driven & @Transactional . Whether in Hibernate or not, I m quite sure @Transactional have to be used at Service layer not @Repository Dao layer. What if you need to handle a transaction that spans across multiple Daos? Dao should be just cohesive components and transaction logic should reside in Service layer.

Pls see http://www.byteslounge.com/tutorials/spring-with-hibernate-persistence-and-transactions-example

But I still see posts where @Transactional is used in Dao layer, and I disagree with it. But if u insist to use @Transactional and @Repository , maybe try put @Transactional on Dao method(s) saveAccount ?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM