问题背景:
项目中使用到了spring来管理bean,事务,以及hibernate的session。同时又用到quartz,执行几个任务如:csv文件解析,将文件数据保存到数据库以及调用ptv服务的geocoding等。在没有使用spring的时候,quartz中job用到的service都是手动new出来的,所以不会有问题,因为加了spring,所以需要spring来生成bean,同时保证事务正常工作。因为hibernate底层调用的是facotry.getCurrentSession()方法获得session,所以如果不加事务,那么就会报错。
问题描述:
如何在生成的job中通过spring获得service,并添加事务管理?
解决方法:
1. 自定义一个Listenner类,继承QuartzInitializerListener类,并把listener配置到web.xml中。(这个原理和spring启动的时候配置的ContextLoaderListener是一个道理,都是实现了ServletContextListener接口。所以在启动的时候可以获得servletContext).
(详细介绍可以参考:http://www.xuebuyuan.com/2041126.html)
2. 重写Listenner类的contextInitialized方法,并把ServletContext放到SchedulerContext中。(SchedulerContext可以看做类似ServletContext的类,多个sheduler共享同一个SchedulerContext)
项目中使用到了spring来管理bean,事务,以及hibernate的session。同时又用到quartz,执行几个任务如:csv文件解析,将文件数据保存到数据库以及调用ptv服务的geocoding等。在没有使用spring的时候,quartz中job用到的service都是手动new出来的,所以不会有问题,因为加了spring,所以需要spring来生成bean,同时保证事务正常工作。因为hibernate底层调用的是facotry.getCurrentSession()方法获得session,所以如果不加事务,那么就会报错。
问题描述:
如何在生成的job中通过spring获得service,并添加事务管理?
解决方法:
1. 自定义一个Listenner类,继承QuartzInitializerListener类,并把listener配置到web.xml中。(这个原理和spring启动的时候配置的ContextLoaderListener是一个道理,都是实现了ServletContextListener接口。所以在启动的时候可以获得servletContext).
(详细介绍可以参考:http://www.xuebuyuan.com/2041126.html)
2. 重写Listenner类的contextInitialized方法,并把ServletContext放到SchedulerContext中。(SchedulerContext可以看做类似ServletContext的类,多个sheduler共享同一个SchedulerContext)
3. 在job类中获得servletContext,再通过servletContext获得webApplicationContext.然后获得transactionmanager添加编程式事务,在业务代码中getBean获得service.
- public class MyQuartZInitializerListener extends QuartzInitializerListener {
- @Override
- public void contextInitialized(ServletContextEvent sce) {
- // TODO Auto-generated method stub
- super.contextInitialized(sce);
- ServletContext sc = sce.getServletContext();
- StdSchedulerFactory fac = (StdSchedulerFactory) sc.getAttribute(QUARTZ_FACTORY_KEY);
- try {
- fac.getScheduler().getContext().put("sct", sc);
- } catch (SchedulerException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
web.xml
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- <listener>
- <listener-class>
- de.haiberg.adman.portal.util.VmapQuartZInitializerListener
- </listener-class>
- </listener>
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- WEB-INF/springdef/spring-datasource.xml
- </param-value>
- </context-param>
- <!-- Hibernate Tranaction Manager -->
- <bean id="transactionManager"
- class="org.springframework.orm.hibernate3.HibernateTransactionManager">
- <property name="sessionFactory" ref="sessionFactory" />
- </bean>
- @Service
- public class MyJob implements StatefulJob {
- private static Logger log = Logger.getLogger(MyJob.class);
- XDaoImpl xDaoImpl;
- public void execute(JobExecutionContext jobContext) throws JobExecutionException {
- ServletContext sct = null;
- try {
- sct = (ServletContext) jobContext.getScheduler().getContext().get("sct");
- } catch (SchedulerException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- WebApplicationContext webctx = (WebApplicationContext) sct
- .getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
- xDaoImpl = webctx.getBean("xDaoImpl", XDaoImpl.class);
- // add transaction manually
- HibernateTransactionManager transactionManager = (HibernateTransactionManager) webctx
- .getBean("transactionManager");
- DefaultTransactionDefinition def = new DefaultTransactionDefinition();
- def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
- TransactionStatus status = transactionManager.getTransaction(def);
- // business code
- //xxxxxxxxxxxxxxxxxxxx
- //xxxxxxxxxxxxxxxxxxxx
- //xxxxxxxxxxxxxxxxxxxx
- transactionManager.commit(status);
- } catch (Exception e) {
- transactionManager.rollback(status);
- log.error("Error[xxxxxx}]: " + e, e);
- }
- }
- }