java 尝试使用 Spring 以正确的顺序销毁 bean

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2083289/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 19:20:21  来源:igfitidea点击:

Trying to destroy beans in the correct order with Spring

javahibernatespringstruts2

提问by Chris

I've got a web app with Spring set up to create my hibernate session factory (singleton) and session and transaction (both are request scoped), but it is destroying the session and transaction in the wrong order. How can i configure it so that the transaction is destroyed before the session? Here's my spring applicationContext.xml file:

我有一个使用 Spring 设置的 Web 应用程序来创建我的休眠会话工厂(单例)以及会话和事务(两者都是请求范围的),但是它以错误的顺序破坏了会话和事务。如何配置它以便在会话之前销毁事务?这是我的 spring applicationContext.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
      "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
  <bean id="hibernateSessionFactory" scope="singleton"
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="configLocation" value="classpath:hibernate.cfg.xml" />
  </bean>

  <!-- The per-http request hibernate session -->
  <bean id="hibernateSession" factory-bean="hibernateSessionFactory"
    factory-method="openSession" destroy-method="close" scope="request" />

  <!--  The per-http request transaction (i need this to be destroyed BEFORE the session) -->
  <bean id="hibernateTransaction" factory-bean="hibernateSession"
    factory-method="beginTransaction" destroy-method="commit" scope="request" />
</beans>

And here's the log that shows it closing the session before it closes the transaction:

这是显示它在关闭事务之前关闭会话的日志:

16111 [http-8080-3] DEBUG org.springframework.beans.factory.support.DisposableBeanAdapter  - Invoking destroy method 'close' on bean with name 'hibernateSession'
16111 [http-8080-3] DEBUG org.hibernate.jdbc.ConnectionManager  - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
16111 [http-8080-3] DEBUG com.mchange.v2.resourcepool.BasicResourcePool  - trace com.mchange.v2.resourcepool.BasicResourcePool@17e4dee [managed: 4, unused: 3, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@19a8416)
16111 [http-8080-3] DEBUG org.springframework.beans.factory.support.DisposableBeanAdapter  - Invoking destroy method 'commit' on bean with name 'hibernateTransaction'
16111 [http-8080-3] DEBUG org.hibernate.transaction.JDBCTransaction  - commit
16111 [http-8080-3] WARN  org.springframework.beans.factory.support.DisposableBeanAdapter  - Invocation of destroy method 'commit' failed on bean with name 'hibernateTransaction'
org.hibernate.SessionException: Session is closed

采纳答案by axtavt

It seems to be that the order of destory method calls for non-singleton-scoped beans is completely out of control. From docs (5.1.4 Using depends-on):

似乎是 destory 方法调用非单例作用域 bean 的顺序完全失控。来自文档(5.1.4 使用依赖):

The depends-on attribute in the bean definition can specify both an initialization time dependency and, in the case of singleton beans only, a corresponding destroy time dependency

bean 定义中的depends-on 属性既可以指定初始化时间依赖,也可以指定仅在单例bean 的情况下对应的销毁时间依赖

You may create a helper object and delegate creation and destruction of your beans to it:

您可以创建一个辅助对象并将 bean 的创建和销毁委托给它:

public class HelperObject
{
    private SessionFactory factory;
    private Session session;
    private Transaction tx;

    public void init()
    {
        session = factory.createSession();
        tx = session.beginTransaction();
    }

    public void destroy()
    {
        tx.commit();
        session.close();
    }

    ...
} 

--

——

<bean id = "helperObject" class = "HelperObject" scope = "request" init-method = "init" destroy-method = "destroy">
    <property name = "factory" ref = "hibernateSessionFactory" />
</bean>

<bean id="hibernateSession" factory-bean="helperObject" 
    factory-method="getSession" scope="request" /> 

<bean id="hibernateTransaction" factory-bean="helperObject" 
    factory-method="getTransaction" scope="request" />

And, after all, perhaps it is not the best way to manage Hibernate sessions and transactions in Spring. Consider using of Spring's built-in Hibernateand transactionssupport.

而且,毕竟,这也许不是在 Spring 中管理 Hibernate 会话和事务的最佳方式。考虑使用 Spring 的内置Hibernate事务支持。

EDIT:Well, the right way to manage transactions is:

编辑:嗯,管理交易的正确方法

  • You don't need request-scoped sessionand transactionbeans
  • You shouldn't call createSessionon the session factory returned by org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean. You can inject this session factory into your beans and call getCurrentSessionwhen you need a session, a it will work fine.
  • You can use declarative transaction management (@Transactionalannotations on the transactional methods). To make it work you should add to your config:
  • 您不需要请求范围sessiontransactionbean
  • 你不应该叫createSession上返回的会话工厂org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean。您可以将此会话工厂注入到您的 bean 中,并getCurrentSession在需要会话时调用,它会正常工作。
  • 您可以使用声明式事务管理(@Transactional事务方法上的注释)。为了让它工作,你应该添加到你的配置中:

.

.

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

<tx:annotation-driven/>
  • For more information, see the links above
  • 有关更多信息,请参阅上面的链接

回答by duffymo

Transactions should be associated with services if you follow the Spring idiom. Sessions are web-tier objects, completely separate from the service tier. It sounds to me like you've made the mistake of entangling your web tier with the service tier. Better to tease them apart; you're unlikely to have this problem with that arrangement.

如果您遵循 Spring 习惯用法,事务应该与服务相关联。会话是 Web 层对象,与服务层完全分离。在我看来,您犯了将 Web 层与服务层纠缠在一起的错误。最好把它们分开;你不太可能在这种安排下遇到这个问题。

回答by meriton

You could declare that hibernateTransactiondepends-onhibernateSession. Since the container will instantiate beans in dependency order (barring cyclic dependencies), and tear them down in reverse dependency order, this should do the trick.

你可以声明这个hibernateTransactiondepends-onhibernateSession。由于容器将按照依赖顺序(循环依赖除外)实例化 bean,并以相反的依赖顺序将它们拆除,这应该可以解决问题。