Настройка фильтра OpenSessionInView с помощью приложения Spring Hibernate
Я работаю над веб-приложением Spring Hibernate
Ранее я загружал конфигурацию Spring с помощью dispatcher-servlet.xml без использования ContextLoaderListener, но когда я реализую шаблон OpenSessionInView, я должен предоставить ContextLoaderListener в web.xml и создать новый 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, без него фильтр не будет работать?
1 ответ
Это связано с тем, что весеннее приложение обычно имеет два контекста: корневой контекст и контекст диспетчера для каждого сервлета.
Идея заключается в том, что приложение может иметь несколько контекстов сервлета с bean-компонентами, такими как контроллеры, и каждый контекст сервлета имеет изолированный родительский корневой контекст, в котором доступны bean-компоненты, общие для всех приложений.
Бины из корневого контекста, такие как фабрика сеансов, могут быть внедрены в бины контекста сервлета (такие как контроллеры), но не наоборот.
OpenSessionInViewFilter извлекает фабрику сеансов из общего корневого контекста приложения (applicationContext.xml), поскольку не может заранее знать, какой контекст сервлета искать.
Код 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 должен найти фабрику сеансов в контексте корневого приложения, и это объясняет, почему вам нужно переместить фабрику сеансов из контекста сервлета (dispatcher-servlet.xml) в корневой контекст (applicationContext.xml),
Для вопроса B не все фильтры приложения имеют эту проблему, это специфические фильтры, которым нужен доступ к некоторому пружинному компоненту, и они должны знать, в каком контексте искать.