Spring注入具体类而不是代理

时间:2013-01-29 16:07:46

标签: java spring jpa

我有一个问题,Spring将DAO对象的代理注入到服务中,但是这个服务被注入到控制器中它是具体的类。这不允许我使用服务范围的事务并分别为每个DAO调用启动事务。这是我期望的行为。

配置:

Controller是带有@Controller注释和构造函数DI的类。

服务:

@Component
@Transactional
public class UserServiceImpl implements UserService { ...}

道:

@Component
@Transactional
public class UserDaoImpl implements UserDao {

JPA配置:    

<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

<bean id="entityManagerFactory"
      class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" >
    <property name="dataSource" ref="dataSource"/>
    <property name="persistenceUnitName" value="xxxPersistenceUnit"/>
    <property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml"/>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        </bean>
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.dialect">${hibernate.dialect}</prop>
            <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
            <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
            <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
        </props>
    </property>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<tx:annotation-driven />

任何人都知道为什么会这样?

4 个答案:

答案 0 :(得分:5)

您的UserServiceImpl很可能是错误地创建了context:component-scan - 请检查Controller表达式,检查其中是否只包含<tx:annotation-driven>个类。

参见in the servlet context 有关组件扫描过滤器的示例。

例如,如果在@Service are constructed twice中声明了事务管理器bean和TransactionInterceptor,那么将仅为根应用程序上下文中的bean创建事务代理(来自root web app context):

  

BeanPostProcessor接口的范围是每个容器。这只是   如果您正在使用容器层次结构相关。如果你定义一个   BeanPostProcessor在一个容器中,它只会对其进行工作   那个容器里的豆子。在一个容器中定义的豆是   即使是在另一个容器中也没有由BeanPostProcessor进行后处理   如果两个容器都属于同一层次结构。

用户服务的事务配置不太可能配置为使用另一个事务管理器(或其他默认传播),但在这种情况下{DA}方法的堆栈跟踪中将出现@Transactional调用。 / p>

如果您了解自己在做什么,那么在Spring中的DAO类上使用Propagation.REQUIRED是绝对可以的 - 存储库或DAO无法打开事务的想法来自于您必须创建样板代码的黑暗时期打开事务并且很难管理事务实例(并且您无法确定如何管理事务)。但是当你使用声明性配置时,事情并没有那么糟糕。 Spring提升了约定约会的风格,大多数方法使用Propagation.REQUIRED事务模式。在Spring中@Transactional是使用@Transactional修饰方法时的默认模式(此传播被硬编码为@Transactional注释声明),这意味着新逻辑事务将映射到同一物理事务,所以使用Session装饰你的DAO类是无害的。

有关Spring中事务传播的参考,请参阅Spring Documentation

在Spring Data JPA中(我很确定他们知道自己在做什么),例如http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/transaction.html#tx-propagation。在某些情况下,这可能很有用,机制与Hibernate允许你从{{1}}获取()一些任意对象进行显示而不声明显式事务(当然这并不意味着框架以某种方式管理)相同没有交易 - 在这种情况下是隐含的)。

答案 1 :(得分:2)

我在理解您所说的内容方面遇到了一些麻烦,但您似乎对每次DAO通话都获得了新的交易感到惊讶,而不仅仅是在服务电话上。不幸的是,这正是你通过在DAO类上放置“@Transactional”而指定的。你的DAO不应该是交易性的,至少如果你遵循通常的模式。如果我理解正确,你应该删除DAO类的@Transactional注释。

答案 2 :(得分:1)

其他响应者是正确的,因为您不应该将您的DAO注释为@Transactional,但要真正理解发生了什么,您应该参考Transaction Propagation section in the Spring Reference Manual。使用@Transactional时的默认传播是REQUIRES_PROPAGATION,因此请仔细阅读。

你的问题不是那么具体,所以我不确定你到底在想什么。

修改:重新阅读您的问题时,您的组件扫描可能存在问题。检查以确保您的<tx:annotation-driven />位于组件扫描服务类的同一应用程序环境中。

答案 3 :(得分:0)

您不应在DAO对象中使用“@Transactional”注释。您正在服务中定义它,并且授予您在服务方法中调用的所有DAO方法在同一事务中执行,当您说“服务范围事务”时,这似乎正是您想要的?

另外,正如建议的那样,您可能希望在UserServiceImpl中将注释从“@Component”更改为“@Service”,并在UserDaoImpl中将注释更改为“@Repository”。

最好的问候。