OpenSessionInViewFilter and Wicket and still running into LazyInitializationExceptions

梦想与她 提交于 2019-12-11 08:35:35

问题


I'm using Spring's OpenSessionInViewFilter in combination with Wicket and I kept running into LazyInitializationExceptions, which I couldn't get resolved. I could see in the logging that the hibernate session was closed before the exception was thrown, so I was obviously doing something wrong.


回答1:


The OSIVFilter must be above the WicketFilter, or else requests won't reach it. The WicketFilter handles page requests itself, it doesn't delegate to other components, such as another servlet (thus, the filter chain stops there).

Another way to do it is to create an implementation of IRequestCycleListener that does the same as the OSIVFilter. I've created such class by modifying Spring's filter code to comply to the new interface, as below:

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);
        }
    }

}


来源:https://stackoverflow.com/questions/15743742/opensessioninviewfilter-and-wicket-and-still-running-into-lazyinitializationexce

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!