Getting your persistence access right when working with background jobs in Spring can be tricky. Most people rely on the Open Session In View pattern using Filters or Interceptors that act on the regular app server threads and close and open sessions for each request.
This technique is not available when you need access to your persistence context from a Quartz Scheduled Job or a TimerTask. The purpose of this tutorials is to show you how you can use Spring AOP proxies to wire a hibernate interceptor that gives you access to the persistence context and it takes cares of closing and opening the sessions for you.
This tutorial is available for download with svn:
svn checkout http://raulrajatutorials.googlecode.com/svn/trunk/ raulrajatutorials-read-only
Comments in the code itself should be self-explanatory if you already have some java + spring experience
And now to the point.
ApplicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <!-- The datasource --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="org.postgresql.Driver" /> <property name="jdbcUrl" value="jdbc:postgresql://localhost:5432/tutorials?autoReconnect=true" /> <property name="user" value="tutorials" /> <property name="password" value="tutorials" /> </bean> <!-- The hibernate session factory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocations"> <list> <value>WEB-INF/conf/hibernate.cfg.xml</value> </list> </property> <property name="configurationClass"> <value>org.hibernate.cfg.AnnotationConfiguration</value> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> <property name="dataSource"> <ref bean="dataSource"/> </property> </bean> <!-- The Hibernate interceptor, which takes care of opening and closing hibernate session around method calls. --> <bean id="hibernateInterceptor" class="org.springframework.orm.hibernate3.HibernateInterceptor"> <property name="sessionFactory"> <ref bean="sessionFactory"/> </property> </bean> <!-- The quartz scheduler in charge of running background jobs --> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean" destroy-method="destroy"> <property name="triggers"> <list> <ref bean="testBackgroundJobTrigger"/> </list> </property> <property name="quartzProperties"> <props> <prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop> <prop key="org.quartz.threadPool.threadCount">20</prop> <prop key="org.quartz.threadPool.threadPriority">2</prop> </props> </property> </bean> <!-- A trigger bean with config info on how to run the background job --> <bean id="testBackgroundJobTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> <property name="jobDetail" ref="testBackgroundJobDetail"/> <property name="startDelay" value="10000"/> <property name="repeatInterval" value="10000" /> </bean> <!-- The actual background job impl that we're going to run --> <bean id="testBackgroundJob" class="com.raulraja.util.jobs.impl.TestBackgroundJobImpl" autowire="autodetect" /> <!-- A proxy with the hibernate interceptor wired in so it can access the persistent context --> <bean id="testBackgroundJobProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target"> <ref bean="testBackgroundJob"/> </property> <property name="proxyInterfaces"> <value>java.lang.Runnable</value> </property> <property name="interceptorNames"> <value>hibernateInterceptor</value> </property> </bean> <!-- Detail info about the job --> <bean id="testBackgroundJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="testBackgroundJobProxy"/> <property name="targetMethod" value="run"/> <property name="concurrent" value="false"/> </bean> </beans>
TestBackgroundJobImpl.java
package com.raulraja.util.jobs.impl; import org.apache.log4j.Logger; /** * Test job that runs on the background */ public class TestBackgroundJobImpl implements Runnable { private final static Logger logger = Logger.getLogger(TestBackgroundJobImpl.class); /** * Do something in the background */ public void run() { logger.debug("doing something in the background"); } }
Output
06/13 15:05:00 DEBUG org.springframework.orm.hibernate3.SessionFactoryUtils - Opening Hibernate Session
06/13 15:05:00 DEBUG com.raulraja.util.jobs.impl.TestBackgroundJobImpl - doing something in the background
06/13 15:05:00 DEBUG org.springframework.orm.hibernate3.HibernateInterceptor - Eagerly flushing Hibernate session
06/13 15:05:00 DEBUG org.springframework.orm.hibernate3.SessionFactoryUtils - Closing Hibernate Session

Thanks mate,
This was totally what I was looking for – you’ve saved me a lot of time as I don’t have to work this one out myself. I’m using Hibernate, Spring, Struts and Jasper so I needed to work out how to get a scheduled job to call DAO’s where I could re-cycle the existing OSIV – rather then re-write anything..
Super..keep up the good work!
Hi rual,
Thank you for the information here.
I am having a similar situation where we have to run several quartz shceduled jobs /triggers to update information.
I tried the proxy apporoach you mentioned but still I can’t get it worked.
The trigger I am trying to use is:
java.lang.Runnable
hibernateInterceptorAU
hibernateInterceptorHK
Can you please help to solve this?
Thanks in advance,
Jani
Hi Jani, try posting your comment again running your code through http://www.elliotswan.com/postable/ first, thanks.
Hi
I would like to know if we can use
1. one hibernate session per multiple quartz jobs.
2. can one have embedded jobs so that the top job has one hibernate session and that hibernate session can be used by the inner job.
The idea is i have to cache some objects that are huge in number .so would like to cache it at frequency of one per day and the inner jobs run every two minute and would be using the cached job and will be hitting the database for other accessory work.
thanks
Hi,
In my opinion you could use ehcache or some other cache system for that. I’m not sure what using the same session will help you with.
Raul,
Thanks for this awesome approach, just one question, if I’m using JPA how could this be possible ? Is it way too different from this ?
Thanks!
Hi Jose,
In the case of JPA it really depends on what impl of JPA you’re using. If you’re using JPA through Hibernate I’m guessing is the same.
Spring comes with a hibernate interceptor built in but the implementation is trivial.
Basically what you want to do for JPA or any other framework that supports transactions is to create an implementation of a org.aopalliance.intercept.MethodInterceptor …
then when you want to provide advice to any method you can wire it with spring with a ProxyFactoryBean like in the example or if you rather do it on java you can do it programmatically like this…
As you can see the technique is much like the Open View in Session filter where you can just get transactions and sessions in the context they’re needed, since you don’t have a thread bound to the web request in this case you can’t use a servlet filter but you can always use a interceptor.