3

我正在开发一个 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>

应用程序上下文.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,没有它过滤器就不能工作吗?

4

1 回答 1

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 并且他们需要知道在哪个上下文中查找的过滤器。

于 2014-01-04T21:20:15.537 回答