使用Spring Hibernate Application配置OpenSessionInView过滤器

时间:2014-01-04 19:34:58

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

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

之前我只使用dispatcher-servlet.xml加载Spring配置而不使用ContextLoaderListener但是当我实现OpenSessionInView模式时,我必须在web.xml中提供ContextLoaderListener并创建一个新的applicationContext.xml&将hibernate配置从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>

一个。谁能告诉我创建一个新的applicationContext.xml并将hibernate代码移动到它的原因?为什么不让代码放在dispatcher-servlet.xml中?

B中。要在Spring中使用过滤器,我们需要一个ContextLoaderListener,而不是过滤器不起作用吗?

1 个答案:

答案 0 :(得分:1)

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

这背后的想法是应用程序可以有多个servlet上下文与bean(如控制器),每个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);
} 

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

对于问题B,并非应用程序的所有过滤器都有此问题,这是需要访问某些spring bean的过滤器的特定情况,他们需要知道要查看的上下文。