有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

JavaSpring正在注入具体的类而不是代理

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

配置:

控制器是带有@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) 个答案

  1. # 1 楼答案

    其他响应者是正确的,因为您不应该将DAO注释为@Transactional,但要真正理解正在发生的事情,您应该参考Transaction Propagation section in the Spring Reference Manual。当使用@Transactional时,默认的传播是REQUIRES_PROPAGATION,所以请具体查看

    你的问题没有那么具体,所以我不确定你到底在找什么

    编辑:重新阅读您的问题后,您的组件扫描可能存在问题。检查以确保<tx:annotation-driven />处于组件扫描服务类的同一应用程序上下文中

  2. # 2 楼答案

    我在理解你说的话时有点困难,但你似乎很惊讶,每次DAO调用都会得到一个新的事务,而不仅仅是服务调用。不幸的是,这正是您在DAO类上添加“@Transactional”所指定的。您的DAO不应该是事务性的,至少如果您遵循通常的模式。如果我理解正确,应该删除DAO类上的@Transactional注释

  3. # 3 楼答案

    您不应该在DAO对象中使用“@Transactional”注释。您在服务中定义它,这将允许在服务方法中调用的所有DAOs方法在同一事务中执行,这似乎正是您所希望的,当您说“服务范围事务”时,对吗

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

    致以最良好的祝愿

  4. # 4 楼答案

    你的UserServiceImpl很可能是错误创建的in the servlet context——请检查context:component-scan表达式,以检查其中是否只包含Controller

    @Service are constructed twice 有关组件扫描过滤器的示例

    例如,如果在root web app context中声明了事务管理器bean和<tx:annotation-driven>,那么将仅为根应用程序上下文(从Spring Documentation)中的bean创建事务代理:

    BeanPostProcessor interfaces are scoped per-container. This is only relevant if you are using container hierarchies. If you define a BeanPostProcessor in one container, it will only do its work on the beans in that container. Beans that are defined in one container are not post-processed by a BeanPostProcessor in another container, even if both containers are part of the same hierarchy.

    不太可能的情况是,用户服务的事务配置被配置为使用另一个事务管理器(或另一个默认传播),但在这种情况下TransactionInterceptor调用将出现在DAO方法的堆栈跟踪中

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

    有关Spring中事务传播的参考,请参见http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/transaction.html#tx-propagation

    在Spring Data JPA中(我很确定他们知道自己在做什么),例如,CRUD methods on repository instances are transactional by default。这在某些情况下可能很有用,这种机制与Hibernate允许您从Session获取()一些任意对象来显示而不声明显式事务时的机制相同(当然,这并不意味着框架以某种方式设法不使用事务——在本例中是隐式的)