Is there a way of intercepting all new Hibernate sessions when they're created? I need to access each Session instance to enable a Hibernate filter with a parameter.
The only solution I've gotten working has involved wrapping the SessionFactory, but this involved a lot of semi nasty hacks as well as it required me to implement around 60 methods, where only a few are interesting.
Hibernate's SessionFactory implementation is for some annoying reason declared final so extending it is not an option. I've also tried aspects and Java proxies without any luck.
I was able to create a JDK proxy:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Date;
import org.hibernate.SessionFactory;
import org.hibernate.engine.SessionFactoryImplementor;
public class SessionFactoryProxyCreator {
public static SessionFactory instance;
public static SessionFactory createProxy(final SessionFactory realSessionFactory) {
ClassLoader cl = SessionFactory.class.getClassLoader();
Class<?>[] interfaces = new Class[] { SessionFactory.class, SessionFactoryImplementor.class };
instance = (SessionFactory)Proxy.newProxyInstance(cl, interfaces, new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("openSession".equals(method.getName())) {
System.out.println("NEW SESSION AT " + new Date());
}
return method.invoke(realSessionFactory, args);
}
});
return instance;
}
}
and you would call this from a custom SessionFactoryBean:
import org.codehaus.groovy.grails.orm.hibernate.ConfigurableLocalSessionFactoryBean;
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class MyConfigurableLocalSessionFactoryBean extends ConfigurableLocalSessionFactoryBean {
public MyConfigurableLocalSessionFactoryBean() {
setCurrentSessionContextClass(MyCurrentSessionContext.class);
}
@Override
protected SessionFactory buildSessionFactory() throws Exception {
setExposeTransactionAwareSessionFactory(false);
return SessionFactoryProxyCreator.createProxy(super.buildSessionFactory());
}
@Override
protected SessionFactory newSessionFactory(Configuration config) throws HibernateException {
setExposeTransactionAwareSessionFactory(false);
return SessionFactoryProxyCreator.createProxy(super.newSessionFactory(config));
}
}
which depends on a modified version of Spring's SpringSessionContext that uses the proxy instead of the real session factory:
import org.hibernate.HibernateException;
import org.hibernate.classic.Session;
import org.hibernate.context.CurrentSessionContext;
import org.hibernate.engine.SessionFactoryImplementor;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
public class MyCurrentSessionContext implements CurrentSessionContext {
public MyCurrentSessionContext(SessionFactoryImplementor sessionFactory) {
// ignore the real sessionFactory, need to use the proxy
}
public Session currentSession() throws HibernateException {
try {
return (org.hibernate.classic.Session)SessionFactoryUtils.doGetSession(
SessionFactoryProxyCreator.instance, false);
}
catch (IllegalStateException e) {
throw new HibernateException(e.getMessage());
}
}
}
This needs to be registered in resources.groovy to replace the standard Grails ConfigurableLocalSessionFactoryBean:
import org.codehaus.groovy.grails.commons.ApplicationHolder as AH
import org.codehaus.groovy.grails.orm.hibernate.events.PatchedDefaultFlushEventListener
beans = {
sessionFactory(MyConfigurableLocalSessionFactoryBean) {
def ds = AH.application.config.dataSource
def hibConfig = AH.application.config.hibernate
dataSource = ref('dataSource')
List hibConfigLocations = []
if (AH.application.classLoader.getResource('hibernate.cfg.xml')) {
hibConfigLocations << 'classpath:hibernate.cfg.xml'
}
def explicitLocations = hibConfig?.config?.location
if (explicitLocations) {
if (explicitLocations instanceof Collection) {
hibConfigLocations.addAll(explicitLocations.collect { it.toString() })
}
else {
hibConfigLocations << hibConfig.config.location.toString()
}
}
configLocations = hibConfigLocations
if (ds?.configClass) {
configClass = ds.configClass
}
hibernateProperties = ref('hibernateProperties')
grailsApplication = ref('grailsApplication', true)
lobHandler = ref('lobHandlerDetector')
entityInterceptor = ref('entityInterceptor')
eventListeners = ['flush': new PatchedDefaultFlushEventListener(),
'pre-load': ref('eventTriggeringInterceptor'),
'post-load': ref('eventTriggeringInterceptor'),
'save': ref('eventTriggeringInterceptor'),
'save-update': ref('eventTriggeringInterceptor'),
'post-insert': ref('eventTriggeringInterceptor'),
'pre-update': ref('eventTriggeringInterceptor'),
'post-update': ref('eventTriggeringInterceptor'),
'pre-delete': ref('eventTriggeringInterceptor'),
'post-delete': ref('eventTriggeringInterceptor')]
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With