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.
Thanks for your post!
I’ve updated your source code to work with JPA 2.0: read at http://chicchiricco.blogspot.com/2011/07/aop-spring-jpa-for-background-threads.html.
I am aware you posted this last year and I’m not as proficient with persistence as I would like to be.
On question I have is:
If you want to retrieve all the the rows from table A. How would you do that in TestBackgroundJobImpl.run()?
I really don’t know which way to go to get the session and to create a Criteria object.
Thanks in advance,
Lucas
Hi Raul,
I found the answer to my own question, I should use autowiring which is what I was using before in my app:
@Autowired
private ObjectService object_service;
public void run() {
List objects = object_service.findAllObject();
}
Thank you for this useful post, seriously, I spent a lot of time trying to figure this out.
I’m sorry for clustering your page with questions.
Thanks once more,
Lucas
Lucas, glad you found the answer and you found the post useful!
Lucas aslo if you’re using JPA you should be able to just inject the persistence context with:
@PersistenceContext
private EntityManager entityManager;
…
entityManager.createQuery(…).setParameter(“…”, …).getResultList();
Hola Raúl,
En mi caso estoy tratando de utilizar un pool de hilos para ejecutar tareas. java.util.concurrent). En mi caso quiero que se vayan resolviendo a medida que van llegando las tareas, no cada cierto período de tiempo.
Como puedo proveer mis workers su correspondiente sesión de Hibernate?
un pseudo-código de lo que quiero hacer sería el siguiente:
ExecutorService servicePool = Executors.newFixedThreadPool(10);
public void processJob(CustomJob job) {
…
servicePool.execute(new RequestJob(job.getId());
…
}
donde Request implementa la interfaz Runnable.
Desde ya, muchas gracias!
saludos
Nicolás, la parte importante del tutorial es que el contenedor de Spring es capaz de crear un proxy para tus servicios el cual abre y cierra el contexto de persistencia alreadedor de invocaciones en los metodos. En tu caso puedes obetner un proxy de “RequestJob” programaticamente de forma que la invocación del metodo a tu elección ya estaría dentro de las sessión de hibernate por ejemplo:
<bean id="testBackgroundJobProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref bean="referenciaATuJobRequestQueImplementaRunnable"/>
</property>
<property name="proxyInterfaces">
<value>java.lang.Runnable</value>
</property>
<property name="interceptorNames">
<value>hibernateInterceptor</value>
</property>
</bean>
y lo obtienes:
applicationContext.getBean(“testBackgroundJobProxy”);
Buena suerte y ya me cuentas
Do you know the difference between HibernateInterceptor and TransactionInterceptor? I am trying to take over some code that is using TransactionInterceptor with the same purpose.
@Alberto, AFAIK the TransactionInterceptor is used to declaratively configure pointcuts that will be surrounded by a transaction. For example methods of a given service. As far as the HibernateInterceptor in this post is mostly to open and close the session automatically in background threads. You should be able to use the TransactionInterceptor to provide a transaction when you think is necessary or @Transactional if you’d rather configure it with annotations.
Thanks a lot!