diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlListableBeanFactoryTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlListableBeanFactoryTests.java index 25848af501..15b8ad914a 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlListableBeanFactoryTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/XmlListableBeanFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2018 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. @@ -42,30 +42,33 @@ import static org.junit.Assert.*; * @author Juergen Hoeller * @since 09.11.2003 */ -@SuppressWarnings({ "rawtypes", "unchecked" }) +@SuppressWarnings({"rawtypes", "unchecked"}) public class XmlListableBeanFactoryTests extends AbstractListableBeanFactoryTests { private DefaultListableBeanFactory parent; private DefaultListableBeanFactory factory; + @Before - public void setUp() { + public void setup() { parent = new DefaultListableBeanFactory(); - Map m = new HashMap(); - m.put("name", "Albert"); + + Map map = new HashMap(); + map.put("name", "Albert"); RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class); - bd1.setPropertyValues(new MutablePropertyValues(m)); + bd1.setPropertyValues(new MutablePropertyValues(map)); parent.registerBeanDefinition("father", bd1); - m = new HashMap(); - m.put("name", "Roderick"); + + map = new HashMap(); + map.put("name", "Roderick"); RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class); - bd2.setPropertyValues(new MutablePropertyValues(m)); + bd2.setPropertyValues(new MutablePropertyValues(map)); parent.registerBeanDefinition("rod", bd2); this.factory = new DefaultListableBeanFactory(parent); - new XmlBeanDefinitionReader(this.factory).loadBeanDefinitions( - new ClassPathResource("test.xml", getClass())); + new XmlBeanDefinitionReader(this.factory).loadBeanDefinitions(new ClassPathResource("test.xml", getClass())); + this.factory.addBeanPostProcessor(new BeanPostProcessor() { @Override public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException { @@ -82,9 +85,10 @@ public class XmlListableBeanFactoryTests extends AbstractListableBeanFactoryTest return bean; } }); + this.factory.addBeanPostProcessor(new LifecycleBean.PostProcessor()); this.factory.addBeanPostProcessor(new ProtectedLifecycleBean.PostProcessor()); - //this.factory.preInstantiateSingletons(); + // this.factory.preInstantiateSingletons(); } @Override @@ -92,6 +96,7 @@ public class XmlListableBeanFactoryTests extends AbstractListableBeanFactoryTest return factory; } + @Test @Override public void count() { @@ -104,19 +109,19 @@ public class XmlListableBeanFactoryTests extends AbstractListableBeanFactoryTest } @Test - public void lifecycleMethods() throws Exception { + public void lifecycleMethods() { LifecycleBean bean = (LifecycleBean) getBeanFactory().getBean("lifecycle"); bean.businessMethod(); } @Test - public void protectedLifecycleMethods() throws Exception { + public void protectedLifecycleMethods() { ProtectedLifecycleBean bean = (ProtectedLifecycleBean) getBeanFactory().getBean("protectedLifecycle"); bean.businessMethod(); } @Test - public void descriptionButNoProperties() throws Exception { + public void descriptionButNoProperties() { TestBean validEmpty = (TestBean) getBeanFactory().getBean("validEmptyWithDescription"); assertEquals(0, validEmpty.getAge()); } @@ -125,7 +130,7 @@ public class XmlListableBeanFactoryTests extends AbstractListableBeanFactoryTest * Test that properties with name as well as id creating an alias up front. */ @Test - public void autoAliasing() throws Exception { + public void autoAliasing() { List beanNames = Arrays.asList(getListableBeanFactory().getBeanDefinitionNames()); TestBean tb1 = (TestBean) getBeanFactory().getBean("aliased"); @@ -224,7 +229,7 @@ public class XmlListableBeanFactoryTests extends AbstractListableBeanFactoryTest } @Test - public void beanPostProcessor() throws Exception { + public void beanPostProcessor() { TestBean kerry = (TestBean) getBeanFactory().getBean("kerry"); TestBean kathy = (TestBean) getBeanFactory().getBean("kathy"); DummyFactory factory = (DummyFactory) getBeanFactory().getBean("&singletonFactory"); diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/Scheduled.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/Scheduled.java index c2aa1df37b..df8100c4cb 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/annotation/Scheduled.java +++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/Scheduled.java @@ -41,6 +41,7 @@ import java.lang.annotation.Target; * composed annotations with attribute overrides. * * @author Mark Fisher + * @author Juergen Hoeller * @author Dave Syer * @author Chris Beams * @since 3.0 @@ -55,10 +56,10 @@ import java.lang.annotation.Target; public @interface Scheduled { /** - * A cron-like expression, extending the usual UN*X definition to include - * triggers on the second as well as minute, hour, day of month, month - * and day of week. e.g. {@code "0 * * * * MON-FRI"} means once per minute on - * weekdays (at the top of the minute - the 0th second). + * A cron-like expression, extending the usual UN*X definition to include triggers + * on the second as well as minute, hour, day of month, month and day of week. + *

E.g. {@code "0 * * * * MON-FRI"} means once per minute on weekdays + * (at the top of the minute - the 0th second). * @return an expression that can be parsed to a cron schedule * @see org.springframework.scheduling.support.CronSequenceGenerator */ diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java index 56f7c2d7a1..a076f9f8af 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java @@ -105,7 +105,7 @@ public class ScheduledAnnotationBeanPostProcessor SmartInitializingSingleton, ApplicationListener, DisposableBean { /** - * The default name of the {@link TaskScheduler} bean to pick up: "taskScheduler". + * The default name of the {@link TaskScheduler} bean to pick up: {@value}. *

Note that the initial lookup happens by type; this is just the fallback * in case of multiple scheduler beans found in the context. * @since 4.2 @@ -231,12 +231,12 @@ public class ScheduledAnnotationBeanPostProcessor Assert.state(this.beanFactory != null, "BeanFactory must be set to find scheduler by type"); try { // Search for TaskScheduler bean... - this.registrar.setTaskScheduler(resolveSchedulerBean(beanFactory, TaskScheduler.class, false)); + this.registrar.setTaskScheduler(resolveSchedulerBean(this.beanFactory, TaskScheduler.class, false)); } catch (NoUniqueBeanDefinitionException ex) { logger.debug("Could not find unique TaskScheduler bean", ex); try { - this.registrar.setTaskScheduler(resolveSchedulerBean(beanFactory, TaskScheduler.class, true)); + this.registrar.setTaskScheduler(resolveSchedulerBean(this.beanFactory, TaskScheduler.class, true)); } catch (NoSuchBeanDefinitionException ex2) { if (logger.isInfoEnabled()) { @@ -252,12 +252,12 @@ public class ScheduledAnnotationBeanPostProcessor logger.debug("Could not find default TaskScheduler bean", ex); // Search for ScheduledExecutorService bean next... try { - this.registrar.setScheduler(resolveSchedulerBean(beanFactory, ScheduledExecutorService.class, false)); + this.registrar.setScheduler(resolveSchedulerBean(this.beanFactory, ScheduledExecutorService.class, false)); } catch (NoUniqueBeanDefinitionException ex2) { logger.debug("Could not find unique ScheduledExecutorService bean", ex2); try { - this.registrar.setScheduler(resolveSchedulerBean(beanFactory, ScheduledExecutorService.class, true)); + this.registrar.setScheduler(resolveSchedulerBean(this.beanFactory, ScheduledExecutorService.class, true)); } catch (NoSuchBeanDefinitionException ex3) { if (logger.isInfoEnabled()) { @@ -340,6 +340,12 @@ public class ScheduledAnnotationBeanPostProcessor return bean; } + /** + * Process the given {@code @Scheduled} method declaration on the given bean. + * @param scheduled the @Scheduled annotation + * @param method the method that the annotation has been declared on + * @param bean the target bean instance + */ protected void processScheduled(Scheduled scheduled, Method method, Object bean) { try { Assert.isTrue(method.getParameterCount() == 0, @@ -456,12 +462,8 @@ public class ScheduledAnnotationBeanPostProcessor // Finally register the scheduled tasks synchronized (this.scheduledTasks) { - Set registeredTasks = this.scheduledTasks.get(bean); - if (registeredTasks == null) { - registeredTasks = new LinkedHashSet<>(4); - this.scheduledTasks.put(bean, registeredTasks); - } - registeredTasks.addAll(tasks); + Set regTasks = this.scheduledTasks.computeIfAbsent(bean, key -> new LinkedHashSet<>(4)); + regTasks.addAll(tasks); } } catch (IllegalArgumentException ex) { diff --git a/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java b/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java index 75693b23ed..45aba7bec2 100644 --- a/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java +++ b/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java @@ -45,6 +45,7 @@ import org.springframework.scheduling.Trigger; import org.springframework.scheduling.TriggerContext; import org.springframework.scheduling.config.CronTask; import org.springframework.scheduling.config.IntervalTask; +import org.springframework.scheduling.config.ScheduledTaskHolder; import org.springframework.scheduling.config.ScheduledTaskRegistrar; import org.springframework.scheduling.support.CronTrigger; import org.springframework.scheduling.support.ScheduledMethodRunnable; @@ -82,7 +83,9 @@ public class ScheduledAnnotationBeanPostProcessorTests { context.registerBeanDefinition("target", targetDefinition); context.refresh(); - Object postProcessor = context.getBean("postProcessor"); + ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class); + assertEquals(1, postProcessor.getScheduledTasks().size()); + Object target = context.getBean("target"); ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) new DirectFieldAccessor(postProcessor).getPropertyValue("registrar"); @@ -108,7 +111,9 @@ public class ScheduledAnnotationBeanPostProcessorTests { context.registerBeanDefinition("target", targetDefinition); context.refresh(); - Object postProcessor = context.getBean("postProcessor"); + ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class); + assertEquals(1, postProcessor.getScheduledTasks().size()); + Object target = context.getBean("target"); ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) new DirectFieldAccessor(postProcessor).getPropertyValue("registrar"); @@ -134,7 +139,9 @@ public class ScheduledAnnotationBeanPostProcessorTests { context.registerBeanDefinition("target", targetDefinition); context.refresh(); - Object postProcessor = context.getBean("postProcessor"); + ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class); + assertEquals(1, postProcessor.getScheduledTasks().size()); + Object target = context.getBean("target"); ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) new DirectFieldAccessor(postProcessor).getPropertyValue("registrar"); @@ -195,7 +202,9 @@ public class ScheduledAnnotationBeanPostProcessorTests { context.registerBeanDefinition("target", targetDefinition); context.refresh(); - Object postProcessor = context.getBean("postProcessor"); + ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class); + assertEquals(2, postProcessor.getScheduledTasks().size()); + Object target = context.getBean("target"); ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) new DirectFieldAccessor(postProcessor).getPropertyValue("registrar"); @@ -231,7 +240,9 @@ public class ScheduledAnnotationBeanPostProcessorTests { context.registerBeanDefinition("target", targetDefinition); context.refresh(); - Object postProcessor = context.getBean("postProcessor"); + ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class); + assertEquals(1, postProcessor.getScheduledTasks().size()); + Object target = context.getBean("target"); ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) new DirectFieldAccessor(postProcessor).getPropertyValue("registrar"); @@ -259,7 +270,9 @@ public class ScheduledAnnotationBeanPostProcessorTests { context.registerBeanDefinition("target", targetDefinition); context.refresh(); - Object postProcessor = context.getBean("postProcessor"); + ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class); + assertEquals(1, postProcessor.getScheduledTasks().size()); + Object target = context.getBean("target"); ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) new DirectFieldAccessor(postProcessor).getPropertyValue("registrar"); @@ -307,7 +320,7 @@ public class ScheduledAnnotationBeanPostProcessorTests { } @Test(expected = BeanCreationException.class) - public void cronTaskWithMethodValidation() throws InterruptedException { + public void cronTaskWithMethodValidation() { BeanDefinition validationDefinition = new RootBeanDefinition(MethodValidationPostProcessor.class); BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class); BeanDefinition targetDefinition = new RootBeanDefinition(CronTestBean.class); @@ -325,7 +338,9 @@ public class ScheduledAnnotationBeanPostProcessorTests { context.registerBeanDefinition("target", targetDefinition); context.refresh(); - Object postProcessor = context.getBean("postProcessor"); + ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class); + assertEquals(1, postProcessor.getScheduledTasks().size()); + Object target = context.getBean("target"); ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) new DirectFieldAccessor(postProcessor).getPropertyValue("registrar"); @@ -350,13 +365,15 @@ public class ScheduledAnnotationBeanPostProcessorTests { context.registerBeanDefinition("target", targetDefinition); context.refresh(); - Object postProcessor = context.getBean("postProcessor"); + ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class); + assertEquals(1, postProcessor.getScheduledTasks().size()); + Object target = context.getBean("target"); - ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) new DirectFieldAccessor( - postProcessor).getPropertyValue("registrar"); + ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) + new DirectFieldAccessor(postProcessor).getPropertyValue("registrar"); @SuppressWarnings("unchecked") - List fixedRateTasks = (List) new DirectFieldAccessor(registrar).getPropertyValue( - "fixedRateTasks"); + List fixedRateTasks = (List) + new DirectFieldAccessor(registrar).getPropertyValue("fixedRateTasks"); assertEquals(1, fixedRateTasks.size()); IntervalTask task = fixedRateTasks.get(0); ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable(); @@ -376,7 +393,9 @@ public class ScheduledAnnotationBeanPostProcessorTests { context.registerBeanDefinition("target", targetDefinition); context.refresh(); - Object postProcessor = context.getBean("postProcessor"); + ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class); + assertEquals(1, postProcessor.getScheduledTasks().size()); + Object target = context.getBean("target"); ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) new DirectFieldAccessor(postProcessor).getPropertyValue("registrar"); @@ -407,7 +426,9 @@ public class ScheduledAnnotationBeanPostProcessorTests { context.registerBeanDefinition("target", targetDefinition); context.refresh(); - Object postProcessor = context.getBean("postProcessor"); + ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class); + assertEquals(1, postProcessor.getScheduledTasks().size()); + Object target = context.getBean("target"); ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) new DirectFieldAccessor(postProcessor).getPropertyValue("registrar"); @@ -447,7 +468,9 @@ public class ScheduledAnnotationBeanPostProcessorTests { context.registerBeanDefinition("target", targetDefinition); context.refresh(); - Object postProcessor = context.getBean("postProcessor"); + ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class); + assertEquals(1, postProcessor.getScheduledTasks().size()); + Object target = context.getBean("target"); ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) new DirectFieldAccessor(postProcessor).getPropertyValue("registrar"); @@ -488,7 +511,9 @@ public class ScheduledAnnotationBeanPostProcessorTests { context.registerBeanDefinition("target", targetDefinition); context.refresh(); - Object postProcessor = context.getBean("postProcessor"); + ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class); + assertEquals(1, postProcessor.getScheduledTasks().size()); + Object target = context.getBean("target"); ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) new DirectFieldAccessor(postProcessor).getPropertyValue("registrar"); @@ -518,7 +543,9 @@ public class ScheduledAnnotationBeanPostProcessorTests { context.getBeanFactory().registerSingleton("schedules", schedules); context.refresh(); - Object postProcessor = context.getBean("postProcessor"); + ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class); + assertEquals(1, postProcessor.getScheduledTasks().size()); + Object target = context.getBean("target"); ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) new DirectFieldAccessor(postProcessor).getPropertyValue("registrar"); @@ -549,7 +576,9 @@ public class ScheduledAnnotationBeanPostProcessorTests { context.registerBeanDefinition("target", targetDefinition); context.refresh(); - Object postProcessor = context.getBean("postProcessor"); + ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class); + assertEquals(1, postProcessor.getScheduledTasks().size()); + Object target = context.getBean("target"); ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) new DirectFieldAccessor(postProcessor).getPropertyValue("registrar"); @@ -574,7 +603,9 @@ public class ScheduledAnnotationBeanPostProcessorTests { context.registerBeanDefinition("target", targetDefinition); context.refresh(); - Object postProcessor = context.getBean("postProcessor"); + ScheduledTaskHolder postProcessor = context.getBean("postProcessor", ScheduledTaskHolder.class); + assertEquals(1, postProcessor.getScheduledTasks().size()); + Object target = context.getBean("target"); ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) new DirectFieldAccessor(postProcessor).getPropertyValue("registrar"); @@ -645,8 +676,7 @@ public class ScheduledAnnotationBeanPostProcessorTests { static class SeveralFixedRatesWithSchedulesContainerAnnotationTestBean { - @Schedules({ @Scheduled(fixedRate = 4000), - @Scheduled(fixedRate = 4000, initialDelay = 2000) }) + @Schedules({@Scheduled(fixedRate = 4000), @Scheduled(fixedRate = 4000, initialDelay = 2000)}) public void fixedRate() { } } @@ -803,6 +833,7 @@ public class ScheduledAnnotationBeanPostProcessorTests { } } + static class PropertyPlaceholderWithCronTestBean { @Scheduled(cron = "${schedules.businessHours}")