【问题标题】:Configuring OpenSessionInView filter with Spring Hibernate Application使用 Spring Hibernate Application 配置 OpenSessionInView 过滤器
【发布时间】:2014-01-22 10:15:58
【问题描述】:

我正在开发一个 Spring Hibernate Web 应用程序

之前我只使用 dispatcher-servlet.xml 加载 Spring 配置而不使用 ContextLoaderListener 但是当我实现 OpenSessionInView 模式时,我必须在 web.xml 中提供一个 ContextLoaderListener 并创建一个新的 applicationContext.xml 并移动休眠配置从 dispatcher-servlet.xml 到 applicationContext.xml。

我对这个改动有些怀疑。

下面是运行良好的代码。 web.xml

<display-name>PetClinic</display-name>

    <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                /WEB-INF/applicationContext.xml
        </param-value>
        </context-param>

     <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>


    <servlet>
      <servlet-name>dispatcher</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
        </init-param>
      <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
      <servlet-name>dispatcher</servlet-name>
      <url-pattern>/forms/*</url-pattern>
    </servlet-mapping>

    <filter>
      <filter-name>hibernateFilter</filter-name>
      <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
      <init-param>
         <param-name>sessionFactoryBeanName</param-name>
         <param-value>sessionFactory</param-value>
      </init-param>
   </filter>

   <filter-mapping>
     <filter-name>hibernateFilter</filter-name>
     <url-pattern>/forms/*</url-pattern>
   </filter-mapping>

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

调度程序-servlet.xml

<context:component-scan base-package="com.petclinic"/>

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

    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">

        <property name="prefix">
            <value>/WEB-INF/view/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>

applicationContext.xml

 <context:annotation-config />

    <!-- <context:property-placeholder> XML element automatically registers a new PropertyPlaceholderConfigurer 
    bean in the Spring Context. -->
    <context:property-placeholder location="classpath:database.properties" />

    <!-- enable the configuration of transactional behavior based on annotations -->
    <tx:annotation-driven transaction-manager="hibernateTransactionManager"/> 

    <!-- Creating DataSource -->
      <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${database.driver}" />
        <property name="url" value="${database.url}" />
        <property name="username" value="${database.user}" />
        <property name="password" value="${database.password}" />
      </bean>

    <!-- To persist the object to database, the instance of SessionFactory interface is created. 
SessionFactory is a singleton instance which implements Factory design pattern. 
SessionFactory loads hibernate.cfg.xml and with the help of TransactionFactory and ConnectionProvider 
implements all the configuration settings on a database. -->

<!-- Configuring SessionFactory -->
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="annotatedClasses">
            <list>
                <value>com.petclinic.Owner</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>             
            </props>
        </property>
    </bean>

<!-- Configuring Hibernate Transaction Manager -->
    <bean id="hibernateTransactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

A.谁能告诉我创建新的 applicationContext.xml 并将休眠代码移至其中的原因?为什么不把代码放在 dispatcher-servlet.xml 中?

B.要在 Spring 中使用过滤器,我们是否需要一个 ContextLoaderListener,没有它,过滤器将无法工作?

【问题讨论】:

  • 我把答案放在下面,因为这是必要的,如果还有问题,请告诉我,但你必须做的事情是正常的 OSIV 工作。我正在创建一个博客,我的第一篇文章是关于 OSIV 的优缺点,如果您有兴趣,请查看blog.jhades.org/open-session-in-view-pattern-pros-and-cons

标签: spring hibernate jakarta-ee spring-mvc open-session-in-view


【解决方案1】:

这是因为 spring 应用程序通常有两个上下文:一个根上下文和一个每个 servlet 调度程序上下文。

这背后的想法是,一个应用程序可以有多个带有 bean 的 servlet 上下文,例如控制器,每个 servlet 上下文都有一个隔离的父根上下文,其中所有应用程序共有的 bean 都可用。

可以将来自根上下文的 bean(例如会话工厂)注入到 servlet 上下文 bean(例如控制器)中,但反之则不行。

OpenSessionInViewFilter 从公共根应用程序上下文 (applicationContext.xml) 检索会话工厂,因为它无法预先知道要查看哪个 servlet 上下文。

OpenSessionInViewFilter 的代码调用lookupSessionFactory,最终又调用了这段代码:

/**
 * Find the root WebApplicationContext for this web application, which is
 * typically loaded via {@link org.springframework.web.context.ContextLoaderListener}.
 * <p>Will rethrow an exception that happened on root context startup,
 * to differentiate between a failed context startup and no context at all.
 * @param sc ServletContext to find the web application context for
 * @return the root WebApplicationContext for this web app, or {@code null} if none
 * @see org.springframework.web.context.WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
 */
public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
    return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
} 

所以这回答了问题 A:OpenSessionInViewFilter 需要在根应用程序上下文中找到会话工厂,这就解释了为什么需要从 servlet 上下文中移动会话工厂(dispatcher-servlet.xml ) 进入根上下文 (applicationContext.xml)。

对于问题 B,并非所有应用程序的过滤器都有这个问题,这是特定于需要访问某些 spring bean 并且他们需要知道在哪个上下文中查找的过滤器。

【讨论】:

  • 完美!!谢谢小伙伴的回复
猜你喜欢
  • 2016-07-13
  • 1970-01-01
  • 2011-08-22
  • 1970-01-01
  • 1970-01-01
  • 2015-08-28
  • 1970-01-01
  • 2015-11-04
  • 2011-02-13
相关资源
最近更新 更多