Tuesday, February 14, 2012

Springframework 3.1 with quartz 2.1.2

I have looked into many samples, but most of spring batch sample was not working on springframework 3.1

It spit it out "java.lang.IncompatibleClassChangeError" error message.

There is an same issue, it mentioned that they have fixed this bug.
https://jira.springsource.org/browse/SPR-8275

But, it was not working.
I have looked into their comments.

I need to use different bean class, just rename most of it with "Factory"

org.springframework.scheduling.quartz.JobDetailBean -> JobDetailFactoryBean like this

Samples batch are below that is running.

<bean id="urlConnectionJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"
  p:jobClass="batch.UrlConnectionJob">
  <property name="jobDataAsMap">
   <map>
    <entry key="informMatchingItemService" value-ref="informMatchingItemService" />
   </map>  
  </property>
 </bean>
 
 <bean id="informMatchingItemService" class="service.InformMatchingItemServiceImpl"/>

 <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean"
  p:jobDetail-ref="urlConnectionJob"
  p:startDelay="20000"
  p:repeatInterval="20000" />
  
 <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
  <property name="triggers">
   <list>
    <ref bean="simpleTrigger" />
   </list>
  </property>
 </bean>


In the End, It's working.
But, bad news is waiting. @Autowired annotation is not working. due to different class lifecycle between spring and quartz. I had to make setter and inject from xml configuration one by one.
There are already different solutions. but, not really meet my expectation and little messy to make clean code.

I decide to put spring batch and quartz out.
It's not necessary for making small batch program for my current project.

There is a good function, I decide to use Spring task and scheduler, that's very simple and easy.
Spring task example and I don't need spring batch jars and quartz jars. of course I can use @Autowired annotation.

http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/scheduling.html



13 comments:

  1. How to configure each job with Transaction Management in Springs.

    I am Using Spring 3.0 and quartz 2.1

    mail@ siva.maadu@gmail.com

    ReplyDelete
  2. Thanks alot for the blog...
    I finally found it after struggling for 2 days...
    However, using the alternative method to Autowired annotation to write the beans in the xml and using the getter and setter methods worked for me :)

    ReplyDelete
  3. Another solution for the @Autowired problem is to implement a class that implements ApplicationContextAware and contains static methods:

    public class ApplicationContextProvider implements ApplicationContextAware {
    private static ApplicationContext ctx = null;

    public static ApplicationContext getApplicationContext() {
    return ctx;
    }

    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
    this.ctx = ctx;
    }
    }

    then you can use the static method to get the context and getContext().getBean("someString") to get the bean.

    ReplyDelete
  4. Hi,
    I was just trying to do the same thing programmatic instead of defining all those stuff in XML definition and tried to run but it was not working for me. Can anyone help me, what is actually going wrong ?

    JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
    jobDetailFactoryBean.setJobClass(MyQuartzJobTest.class);

    SimpleTriggerFactoryBean simpleTriggerFactoryBean = new SimpleTriggerFactoryBean();
    simpleTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());
    simpleTriggerFactoryBean.setStartDelay(20000);
    simpleTriggerFactoryBean.setRepeatInterval(20000);

    SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
    schedulerFactoryBean.setTriggers(new Trigger[]{simpleTriggerFactoryBean.getObject()});

    Scheduler scheduler = schedulerFactoryBean.getObject();
    try{
    //scheduler.start();
    schedulerFactoryBean.start();
    }catch(Exception e){
    System.out.println(" ..... Scheduler can not be started ... : error : "+e);
    e.printStackTrace();
    }

    ReplyDelete
  5. Hi,
    Bellow code is also not working shows java.lang.NullPointerException
    try{
    scheduler.start();
    //schedulerFactoryBean.start();
    }catch(Exception e){
    System.out.println(" ..... Scheduler can not be started ... : error : "+e);
    e.printStackTrace();
    }

    ReplyDelete
    Replies
    1. Hi pragflume,
      I'm faced with similar problem, did you solved the problem?

      Delete
  6. Hi paragflume,
    I don't know if you still need to know what was wrong in your code.
    I Googled a lot without finding the correct answer: This problem is very common to all Who don't want to use the common Spring managed bean application context configuration file.
    This is due to a lack in Spring documentation (thousand of pages, but the simplest things are always misst)
    After several try I found myself that the correct solution is simple:
    after programmatically set the requested properties in the required Spring factory or Spring bean, check if the bean contains a metod called .afterPropertiesSet();
    If exists call it!!!

    In your example, you need to call it three times:

    //first after setting JobDetailFactoryBean property:

    JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
    jobDetailFactoryBean.setJobClass(MyQuartzJobTest.class);
    JobDetailFactoryBean.afterPropertiesSet();

    //second after setting SimpleTriggerFactoryBean property:

    SimpleTriggerFactoryBean simpleTriggerFactoryBean = new SimpleTriggerFactoryBean();
    simpleTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());
    simpleTriggerFactoryBean.setStartDelay(20000);
    simpleTriggerFactoryBean.setRepeatInterval(20000);
    simpleTriggerFactoryBean.afterPropertiesSet();


    //Third after setting SchedulerFactoryBean property:

    SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
    schedulerFactoryBean.setTriggers(new Trigger[]{simpleTriggerFactoryBean.getObject()});

    Scheduler scheduler = schedulerFactoryBean.getObject();
    try{
    schedulerFactoryBean.afterPropertiesSet();
    schedulerFactoryBean.start();
    }catch(Exception e){
    System.out.println(" ..... Scheduler can not be started ... : error : "+e);
    e.printStackTrace();
    }
    Hint: I is better to define the schedulerFactoryBean in the Spring context and not programmatically, so that it wuill be available anywhere in you code to gain access to "Scheduler" instance ;-)

    Hoping this would be helpful for you and anybody else is driving Crazy with Spring-Quartz.

    ReplyDelete
  7. Thanks for the example, works fine for me !!

    ReplyDelete
  8. Bài viết của Admin thật hay, thank bạn đã chia sẻ.
    Xem tại website : Thạch anh vụn

    ReplyDelete
  9. Bài post của Admin rất cần thiết, cám ơn bạn đã chia sẻ.
    Xem tại website : Gia công thạch anh

    ReplyDelete
  10. Trí tuệ của bạn khá được, thank bạn vừa share.
    Xem thêm tại website: Vòng đeo đá thạch anh

    ReplyDelete
  11. Kiến thức của tác giả rất hay, thank bạn đã chia sẻ.
    Trang tham khảo : Tỳ hưu thạch anh

    ReplyDelete