使用Spring Hibernate应用程序配置OpenSessionInView筛选器

使用Spring Hibernate应用程序配置OpenSessionInView筛选器,spring,hibernate,jakarta-ee,spring-mvc,open-session-in-view,Spring,Hibernate,Jakarta Ee,Spring Mvc,Open Session In View,我正在开发一个SpringHibernateWeb应用程序 之前我只使用dispatcher-servlet.xml加载Spring配置,没有使用ContextLoaderListener,但是当我实现OpenSessionInView模式时,我必须在web.xml中提供ContextLoaderListener,并创建一个新的applicationContext.xml&将hibernate配置从dispatcher-servlet.xml移到applicationContext.xml 我对

我正在开发一个SpringHibernateWeb应用程序

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

我对这一变化有些怀疑

下面是工作正常的代码。 web.xml

宠物诊所 上下文配置位置 /WEB-INF/applicationContext.xml org.springframework.web.context.ContextLoaderListener 调度员 org.springframework.web.servlet.DispatcherServlet 上下文配置位置 /WEB-INF/dispatcher-servlet.xml 1. 调度员 /形式/* 冬眠过滤器 org.springframework.orm.hibernate3.support.OpenSessionInViewFilter sessionFactoryBeanName 会话工厂 冬眠过滤器 /形式/* index.jsp dispatcher-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>

/WEB-INF/view/
.jsp
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>

com.petclinic.Owner
${hibernate.dial}
${hibernate.show_sql}
${hibernate.hbm2ddl.auto}
A.谁能告诉我创建新applicationContext.xml并将hibernate代码移到其中的原因吗?为什么不让代码放在dispatcher-servlet.xml中呢


B.要在Spring中使用过滤器,我们需要ContextLoaderListener吗?没有它,过滤器不会工作吗?

这是因为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);
} 
/**
*查找此web应用程序的根WebApplicationContext,它是
*通常通过{@link org.springframework.web.context.ContextLoaderListener}加载。
*将重新显示根上下文启动时发生的异常,
*区分上下文启动失败和完全没有上下文。
*@param sc ServletContext查找的web应用程序上下文
*@返回此web应用程序的根WebApplicationContext,如果没有,则返回{@code null}
*@请参阅org.springframework.web.context.WebApplicationContext#ROOT_web_APPLICATION_context_属性
*/
公共静态WebApplicationContext getWebApplicationContext(ServletContext sc){
返回getWebApplicationContext(sc,WebApplicationContext.ROOT\u WEB\u应用程序\u上下文\u属性);
} 
这就回答了问题A:OpenSessionInViewFilter需要在根应用程序上下文中找到会话工厂,这就解释了为什么需要将会话工厂从servlet上下文(dispatcher servlet.xml)移动到根上下文(applicationContext.xml)


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

我将答案放在下面,说明为什么这是必要的,如果仍然有问题,请告诉我,但您必须执行的操作对于OSIV正常工作。我正在开一个博客,我的第一篇文章是关于OSIV的优点和缺点,如果你感兴趣的话,请看一看!!谢谢你的回复,伙计
/**
 * 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);
}