diff --git a/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java b/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java index 6b2c4ab675..a4d1a410d8 100644 --- a/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java +++ b/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationListener; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationUtils; @@ -113,6 +114,10 @@ public class ScheduledAnnotationBeanPostProcessor implements BeanPostProcessor, String cron = annotation.cron(); if (!"".equals(cron)) { processedSchedule = true; + if (applicationContext instanceof ConfigurableApplicationContext) { + cron = ((ConfigurableApplicationContext) applicationContext) + .getBeanFactory().resolveEmbeddedValue(cron); + } cronTasks.put(runnable, cron); } long fixedDelay = annotation.fixedDelay(); diff --git a/org.springframework.context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java b/org.springframework.context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java index bf8aec23fa..47e59a6357 100644 --- a/org.springframework.context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java +++ b/org.springframework.context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java @@ -23,12 +23,14 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.Map; +import java.util.Properties; import org.junit.Test; import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.support.StaticApplicationContext; import org.springframework.scheduling.config.ScheduledTaskRegistrar; @@ -160,6 +162,66 @@ public class ScheduledAnnotationBeanPostProcessorTests { assertEquals("0 0 * * * ?", cronTasks.values().iterator().next()); } + @Test + public void propertyPlaceholderWithCronExpression() { + String businessHoursCronExpression = "0 0 9-17 * * MON-FRI"; + StaticApplicationContext context = new StaticApplicationContext(); + BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class); + BeanDefinition placeholderDefinition = new RootBeanDefinition(PropertyPlaceholderConfigurer.class); + Properties properties = new Properties(); + properties.setProperty("schedules.businessHours", businessHoursCronExpression); + placeholderDefinition.getPropertyValues().addPropertyValue("properties", properties); + BeanDefinition targetDefinition = new RootBeanDefinition( + ScheduledAnnotationBeanPostProcessorTests.PropertyPlaceholderTestBean.class); + context.registerBeanDefinition("placeholder", placeholderDefinition); + context.registerBeanDefinition("postProcessor", processorDefinition); + context.registerBeanDefinition("target", targetDefinition); + context.refresh(); + Object postProcessor = context.getBean("postProcessor"); + Object target = context.getBean("target"); + ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) + new DirectFieldAccessor(postProcessor).getPropertyValue("registrar"); + Map cronTasks = (Map) + new DirectFieldAccessor(registrar).getPropertyValue("cronTasks"); + assertEquals(1, cronTasks.size()); + MethodInvokingRunnable runnable = (MethodInvokingRunnable) cronTasks.keySet().iterator().next(); + Object targetObject = runnable.getTargetObject(); + String targetMethod = runnable.getTargetMethod(); + assertEquals(target, targetObject); + assertEquals("x", targetMethod); + assertEquals(businessHoursCronExpression, cronTasks.values().iterator().next()); + } + + @Test + public void propertyPlaceholderForMetaAnnotation() { + String businessHoursCronExpression = "0 0 9-17 * * MON-FRI"; + StaticApplicationContext context = new StaticApplicationContext(); + BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class); + BeanDefinition placeholderDefinition = new RootBeanDefinition(PropertyPlaceholderConfigurer.class); + Properties properties = new Properties(); + properties.setProperty("schedules.businessHours", businessHoursCronExpression); + placeholderDefinition.getPropertyValues().addPropertyValue("properties", properties); + BeanDefinition targetDefinition = new RootBeanDefinition( + ScheduledAnnotationBeanPostProcessorTests.PropertyPlaceholderMetaAnnotationTestBean.class); + context.registerBeanDefinition("postProcessor", processorDefinition); + context.registerBeanDefinition("placeholder", placeholderDefinition); + context.registerBeanDefinition("target", targetDefinition); + context.refresh(); + Object postProcessor = context.getBean("postProcessor"); + Object target = context.getBean("target"); + ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) + new DirectFieldAccessor(postProcessor).getPropertyValue("registrar"); + Map cronTasks = (Map) + new DirectFieldAccessor(registrar).getPropertyValue("cronTasks"); + assertEquals(1, cronTasks.size()); + MethodInvokingRunnable runnable = (MethodInvokingRunnable) cronTasks.keySet().iterator().next(); + Object targetObject = runnable.getTargetObject(); + String targetMethod = runnable.getTargetMethod(); + assertEquals(target, targetObject); + assertEquals("y", targetMethod); + assertEquals(businessHoursCronExpression, cronTasks.values().iterator().next()); + } + @Test(expected = BeanCreationException.class) public void emptyAnnotation() { StaticApplicationContext context = new StaticApplicationContext(); @@ -296,4 +358,26 @@ public class ScheduledAnnotationBeanPostProcessorTests { } } + + private static class PropertyPlaceholderTestBean { + + @Scheduled(cron = "${schedules.businessHours}") + public void x() { + } + } + + + @Scheduled(cron = "${schedules.businessHours}") + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + private static @interface BusinessHours {} + + + private static class PropertyPlaceholderMetaAnnotationTestBean { + + @BusinessHours + public void y() { + } + } + }