我将 Spring 的 OpenSessionInViewFilter 与 Wicket 结合使用,但我一直遇到 LazyInitializationExceptions,我无法解决。我可以在日志中看到休眠会话在引发异常之前已关闭,所以我显然做错了。
问问题
538 次
1 回答
2
OSIVFilter 必须在 WicketFilter 之上,否则请求将无法到达。WicketFilter 自己处理页面请求,它不委托给其他组件,例如另一个 servlet(因此,过滤器链停在那里)。
另一种方法是创建一个IRequestCycleListener
与 OSIVFilter 相同的实现。我通过修改 Spring 的过滤器代码以符合新接口创建了这样的类,如下所示:
import org.apache.wicket.MetaDataKey;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.request.cycle.AbstractRequestCycleListener;
import org.apache.wicket.request.cycle.RequestCycle;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.orm.hibernate4.SessionFactoryUtils;
import org.springframework.orm.hibernate4.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
public class OpenSessionInViewRequestCycleListener extends AbstractRequestCycleListener {
protected final Logger logger = LoggerFactory.getLogger(getClass());
public static final String DEFAULT_SESSION_FACTORY_BEAN_NAME = "sessionFactory";
private static final MetaDataKey<Boolean> PARTICIPATE = new MetaDataKey<Boolean>() {
};
private static final MetaDataKey<SessionFactory> SESSION_FACTORY = new MetaDataKey<SessionFactory>() {
};
private String sessionFactoryBeanName = DEFAULT_SESSION_FACTORY_BEAN_NAME;
private final WebApplication application;
public OpenSessionInViewRequestCycleListener(WebApplication application) {
this.application = application;
}
/**
* Set the bean name of the SessionFactory to fetch from Spring's
* root application context. Default is "sessionFactory".
* @see #DEFAULT_SESSION_FACTORY_BEAN_NAME
*/
public void setSessionFactoryBeanName(String sessionFactoryBeanName) {
this.sessionFactoryBeanName = sessionFactoryBeanName;
}
/**
* Return the bean name of the SessionFactory to fetch from Spring's
* root application context.
*/
protected String getSessionFactoryBeanName() {
return this.sessionFactoryBeanName;
}
@Override
public void onBeginRequest(RequestCycle cycle) {
SessionFactory sessionFactory = lookupSessionFactory(cycle);
cycle.setMetaData(SESSION_FACTORY, sessionFactory);
cycle.setMetaData(PARTICIPATE, false);
if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
// Do not modify the Session: just set the participate flag.
cycle.setMetaData(PARTICIPATE, true);
}
else {
logger.debug("Opening Hibernate Session in OpenSessionInViewRequestCycleListener");
Session session = openSession(sessionFactory);
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
}
}
@Override
public void onEndRequest(RequestCycle cycle) {
if (!cycle.getMetaData(PARTICIPATE)) {
SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.unbindResource(cycle.getMetaData(SESSION_FACTORY));
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
SessionFactoryUtils.closeSession(sessionHolder.getSession());
}
}
/**
* Look up the SessionFactory that this filter should use,
* taking the current HTTP request as argument.
* <p>The default implementation delegates to the {@link #lookupSessionFactory()}
* variant without arguments.
* @param cycle the current request
* @return the SessionFactory to use
*/
protected SessionFactory lookupSessionFactory(RequestCycle cycle) {
return lookupSessionFactory();
}
/**
* Look up the SessionFactory that this filter should use.
* <p>The default implementation looks for a bean with the specified name
* in Spring's root application context.
* @return the SessionFactory to use
* @see #getSessionFactoryBeanName
*/
protected SessionFactory lookupSessionFactory() {
if (logger.isDebugEnabled()) {
logger.debug("Using SessionFactory '" + getSessionFactoryBeanName() + "' for OpenSessionInViewFilter");
}
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(this.application.getServletContext());
return wac.getBean(getSessionFactoryBeanName(), SessionFactory.class);
}
/**
* Open a Session for the SessionFactory that this filter uses.
* <p>The default implementation delegates to the
* {@code SessionFactory.openSession} method and
* sets the {@code Session}'s flush mode to "MANUAL".
* @param sessionFactory the SessionFactory that this filter uses
* @return the Session to use
* @throws DataAccessResourceFailureException if the Session could not be created
* @see org.hibernate.FlushMode#MANUAL
*/
protected Session openSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
try {
Session session = sessionFactory.openSession();
session.setFlushMode(FlushMode.MANUAL);
return session;
} catch (HibernateException ex) {
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
}
}
}
于 2013-04-01T16:08:45.993 回答