View Full Version : Feature: @Scheduled with @Value cron expression?
axel.knauf
Jan 13th, 2010, 07:04 AM
Hi.
I am using Spring 3.0.0.RELEASE and tried to setup a scheduled job using the @Scheduled annotation with a configurable cron expression (stored in a properties file). My intuitive approach was to annotate my service method (in a @Service component) with @Scheduled and use Spring's Expression Language with the @Value annotation for retrieval of the properties value. Here's an example:
@Service public class SomeService .. {
// ..
@Scheduled(cron = @Value("#{ applicationProps['rates.refresh.cron']}"))
public void refreshRates() throws ... { .. }
// ...
}
..with my applicationContext.xml containing these settings:
<context:component-scan base-package="com.example.some.package" />
<task:annotation-driven />
<util:properties id="applicationProps" location="/WEB-INF/classes/properties/application.properties" />
Obviously this fails since @Scheduled's "cron" attribute expects a constant String value to be assigned.
I finally implemented this behaviour using the XML-based task configuration:
<task:scheduled-tasks>
<task:scheduled ref="someService" method="refreshRates" cron="#{applicationProps['rates.refresh.cron']}" />
</task:scheduled-tasks>
..which forces me to ensure the proper service bean name using..
@Service(value="someService") public class SomeService..
..so that resolving my bean reference inside the "task:scheduled" section works.
Wouldn't it be a neat feature to be able to setup task scheduling using annotations only with my first approach, or do I miss some point here?
For your reference, here are the links to Spring's Expression Language (http://static.springsource.org/spring/docs/3.0.x/reference/htmlsingle/spring-framework-reference.html#new-feature-elhttp://) and the @Scheduled Annotation documentation (http://static.springsource.org/spring/docs/3.0.x/reference/htmlsingle/spring-framework-reference.html#scheduling-annotation-support-scheduled).
Thanks for any feedback about this, digging into Spring 3 reveals many great improvements!
Cheers,
Axel
sslavic
Jan 13th, 2010, 05:59 PM
ScheduledAnnotationBeanPostProcessor uses ConfigurableApplicationContext's resolveEmbeddedValue to resolve cron attribute value. AbstractBeanFactory implements ConfigurableBeanFactory, and it's resolveEmbeddedValue method implementation uses StringValueResolver implementations to resolveStringValue. There is only one StringValueResolver implementation, PlaceholderResolvingStringValueResolver which makes use of PropertyPlaceholderHelper to resolveStringValue, ...
Basically one should be able to reference properties using property placeholder expression ("${...}") in @Scheduled cron attribute value, just register ProperyPlaceholderConfigurer in your context XML, e.g. to point to properties file with configured cron expression property.
axel.knauf
Jan 14th, 2010, 02:16 AM
Hi sslavic.
I gave your suggestion an try and added this section in my XML context:
<task:annotation-driven />
<util:properties id="applicationProps"
location="/WEB-INF/classes/properties/application.properties" />
<bean class="org.springframework.beans.factory.config.PropertyP laceholderConfigurer" p:properties-ref="applicationProps" />
and my service implementation adjusted to:
@Scheduled(cron = "${rates.refresh.cron}")
public void refreshRates() throws ... { .. }
But nevertheless I get the following exception when deploying my application:
java.lang.IllegalArgumentException: cron expression must consist of 6 fields (found 1 in ${rates.refresh.cron})
Obviously the property is not resolved and the placeholder string itself is being interpreted as cron expression. Honestly, I expected that since PropertyPlaceholderConfigurer only replaces tokens inside the XML context definition and not in Java code. That's what the new @Value annotation is for, which I mentioned in my initial posting.
But nevertheless thanks for the suggestion, sslavic. I appreciate your feedback.
Cheers,
Axel
sslavic
Jan 14th, 2010, 03:35 AM
When analyzing spring-framework sources I was using spring-framework trunk (https://src.springframework.org/svn/spring-framework/trunk), where ScheduledAnnotationBeanPostProcessor has been changed since 3.0.0.RELEASE, to add support for property placeholders as cron attribute values (see related issue (http://jira.springframework.org/browse/SPR-6670) in spring-framework issue tracker), so this will be available in 3.0.1.RELEASE. If you can't wait for that to happen, you can build spring trunk yourself, in which case this SpringSource blog (http://blog.springsource.com/2009/03/03/building-spring-3/) might be useful.
axel.knauf
Jan 14th, 2010, 06:33 AM
Thanks sslavic for the detailed reply and the issue report you pointed me to.
Since the 3.0.1 release is due already 25. January[0], I will be happy to wait until then. In the meantime, my workaround using the XML based configuration (described in my first posting) will be fine.
Cheers,
Axel
--
[0] Weird, but rich formatting is disabled for me ATM, so here's the link as footnote:
- http://jira.springframework.org/browse/SPR/fixforversion/11331
axel.knauf
Feb 19th, 2010, 02:37 AM
Spring 3.0.1 has just been released (http://www.springsource.org/download) and I now readjusted my setup - here's my current, and working, state.
In my applicationContext.xml I have a PropertiesPlaceholder, its backing Properties and the task scheduling set to use annotations:
<util:properties id="applicationProps" location="/WEB-INF/classes/properties/application.properties" />
<context:property-placeholder properties-ref="applicationProps" />
..
<task:annotation-driven />
And the service method which shall be called using the @Scheduled annotation now looks like this:
@Scheduled(cron = "${rates.refresh.cron}")
public void refreshRates() throws .. { .. }
..with the service implementation class being annotated as @Service as mentioned in my initial post.
With Spring 3.0.1 this work perfectly out of the box and I can drop my XML configuration for the task scheduling which I used as interim solution. Thanks for this great new release!
Cheers,
Axel
luvfort
May 7th, 2010, 06:13 PM
Hi Alex,
This is working for me as well. However when I update the value through the JMX, the scheduler is not taking the latest?
axel.knauf
May 8th, 2010, 05:09 AM
Hi luvfort.
This is working for me as well. However when I update the value through the JMX, the scheduler is not taking the latest?
I guess the ScheduledAnnotationBeanPostProcessor only sets up the scheduling mechanism _once_ upon application context initialization. This is why a changed (cron) schedule may not be applied when modified during runtime (which is what I guess you do using JMX).
Perhaps the chapter about task scheduling (http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/scheduling.html#scheduling-annotation-support-scheduled)in the reference docs allows to find a solution (don't have the time to look myself right now).
Cheers & HTH,
Axel
pamlwong
Jul 29th, 2010, 09:25 AM
can show me an example of application.properties that u included in you context:property-placeholder?
axel.knauf
Jul 31st, 2010, 05:22 AM
Hi pamlwong.
can show me an example of application.properties that u included in you context:property-placeholder?
Of course :) My application.properties contains various settings, the one for the cron scheduled job was:
# run refresh job every day a 9am
rates.refresh.cron=0 0 9 * * *
The syntax how you can define schedules is described in the API for CronSquenceGenerator (http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/scheduling/support/CronSequenceGenerator.html) or in the reference documentation (http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/scheduling.html#scheduling-annotation-support-scheduled), here's an excerpt from the API:
Example patterns:
* "0 0 * * * *" = the top of every hour of every day.
* "*/10 * * * * *" = every ten seconds.
* "0 0 8-10 * * *" = 8, 9 and 10 o'clock of every day.
* "0 0/30 8-10 * * *" = 8:00, 8:30, 9:00, 9:30 and 10 o'clock every day.
* "0 0 9-17 * * MON-FRI" = on the hour nine-to-five weekdays
* "0 0 0 25 12 ?" = every Christmas Day at midnight
I hope this helps.
Cheers,
Axel
pamlwong
Aug 6th, 2010, 03:18 AM
Thanks for ur prompt reply.
exception:
org.springframework.beans.factory.xml.XmlBeanDefin itionStoreException: Line 60 in XML document from class path resource [applicationContext.xml] is invalid; nested exception is org.xml.sax.SAXParseException: The prefix "util" for element "util:properties" is not bound.
My config file:
<task:annotation-driven executor="taskExecutor" scheduler="taskScheduler">
<util:properties id="applicationProps" location="/WEB-INF/resources/crontab.properties" />
<context:property-placeholder properties-ref="applicationProps" />
</task:annotation-driven>
my Crontab.properties
rates.refresh.cron=1/3 * * * * *
im very new to this, xml and i have no idea whats goin on. please advise
pamlwong
Aug 6th, 2010, 04:05 AM
i realise i missed out the
xmlns:util="http://www.springframework.org/schema/util"
&
xsi:schemaLocation="
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd"
and i have change my config to
<task:annotation-driven executor="taskExecutor" scheduler="taskScheduler"/>
<context:property-placeholder location="classpath:crontab.properties"/>
But there is another <context:property-placeholder... > at another xml file. ended up the next <context:property-placeholder... > seems like got problem when loading.
pamlwong
Aug 6th, 2010, 04:26 AM
i realise i missed out the
xmlns:util="http://www.springframework.org/schema/util"
&
xsi:schemaLocation="
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd"
and i have change my config to
<task:annotation-driven executor="taskExecutor" scheduler="taskScheduler"/>
<context:property-placeholder location="classpath:crontab.properties"/>
But there is another <context:property-placeholder... > at another xml file. ended up the next <context:property-placeholder... > seems like got problem when loading.
Lastest update:
i am using spring 3 + tomcat currently.
It seems like it will only load the 1st context: property-placeholder. so i have to put all the to be loaded properties file in same place just like this:
<context: property-placeholder location="classpath:jdbc.properties, classpath:crontab.properties"/>
sheik
Feb 22nd, 2011, 01:38 AM
thank you . it worked !
eitan.suez
Jan 20th, 2012, 03:04 PM
..And the service method which shall be called using the @Scheduled annotation now looks like this:
@Scheduled(cron = "${rates.refresh.cron}")
public void refreshRates() throws .. { .. }
..with the service implementation class being annotated as @Service as mentioned in my initial post.
With Spring 3.0.1 this work perfectly out of the box and I can drop my XML configuration for the task scheduling which I used as interim solution. Thanks for this great new release!
Cheers,
Axel
that's great. anyone know how to you make this work with a PeriodicTrigger?
i.e. @Scheduler(fixedRate=...).
the fixedRate attribute is type long, not string. with a cron expression, the types match.
so hard-coding the value works:
@Scheduler(fixedRate=5000)
but i cannot trick it into bringing in a placeholder:
@Scheduler(fixedRate="${someprop}")
/ eitan
hareendran
Feb 26th, 2012, 01:19 PM
i had used the xml <task :scheduler /> but hit upon a strange issue like if default-init-lazy=true for the beans the process is not triggered. once i remove lazy tag it works like chime. Any ssugestion or have i made any grave mistake?
savgur
Mar 20th, 2012, 08:29 AM
What about web.xml environment entries? Is it possible to get cron expression from web.xml?
michal26
Mar 27th, 2012, 02:48 AM
I think you should use JMX.
Powered by vBulletin® Version 4.2.1 Copyright © 2013 vBulletin Solutions, Inc. All rights reserved.