@Scheduled reliably applies after other post-processors and shuts down before TaskScheduler

Issue: SPR-14692
Issue: SPR-15067
(cherry picked from commit edc62be)
This commit is contained in:
Juergen Hoeller
2016-12-29 22:35:10 +01:00
parent 794580ffcd
commit fd21e0e69a
5 changed files with 124 additions and 27 deletions

View File

@@ -18,11 +18,14 @@ package org.springframework.scheduling.annotation;
import java.util.concurrent.atomic.AtomicInteger;
import org.aspectj.lang.annotation.Aspect;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -46,6 +49,7 @@ import static org.mockito.BDDMockito.*;
* as @Transactional or @Async processing.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
*/
@SuppressWarnings("resource")
@@ -76,11 +80,11 @@ public class ScheduledAndTransactionalAnnotationIntegrationTests {
ctx.register(Config.class, SubclassProxyTxConfig.class, RepoConfigA.class);
ctx.refresh();
Thread.sleep(100); // allow @Scheduled method to be called several times
Thread.sleep(100); // allow @Scheduled method to be called several times
MyRepository repository = ctx.getBean(MyRepository.class);
CallCountingTransactionManager txManager = ctx.getBean(CallCountingTransactionManager.class);
assertThat("repository is not a proxy", AopUtils.isAopProxy(repository), equalTo(true));
assertThat("repository is not a proxy", AopUtils.isCglibProxy(repository), equalTo(true));
assertThat("@Scheduled method never called", repository.getInvocationCount(), greaterThan(0));
assertThat("no transactions were committed", txManager.commits, greaterThan(0));
}
@@ -91,15 +95,28 @@ public class ScheduledAndTransactionalAnnotationIntegrationTests {
ctx.register(Config.class, JdkProxyTxConfig.class, RepoConfigB.class);
ctx.refresh();
Thread.sleep(50); // allow @Scheduled method to be called several times
Thread.sleep(100); // allow @Scheduled method to be called several times
MyRepositoryWithScheduledMethod repository = ctx.getBean(MyRepositoryWithScheduledMethod.class);
CallCountingTransactionManager txManager = ctx.getBean(CallCountingTransactionManager.class);
assertThat("repository is not a proxy", AopUtils.isAopProxy(repository), is(true));
assertThat("repository is not a proxy", AopUtils.isJdkDynamicProxy(repository), is(true));
assertThat("@Scheduled method never called", repository.getInvocationCount(), greaterThan(0));
assertThat("no transactions were committed", txManager.commits, greaterThan(0));
}
@Test
public void withAspectConfig() throws InterruptedException {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AspectConfig.class, MyRepositoryWithScheduledMethodImpl.class);
ctx.refresh();
Thread.sleep(100); // allow @Scheduled method to be called several times
MyRepositoryWithScheduledMethod repository = ctx.getBean(MyRepositoryWithScheduledMethod.class);
assertThat("repository is not a proxy", AopUtils.isCglibProxy(repository), is(true));
assertThat("@Scheduled method never called", repository.getInvocationCount(), greaterThan(0));
}
@Configuration
@EnableTransactionManagement
@@ -108,7 +125,7 @@ public class ScheduledAndTransactionalAnnotationIntegrationTests {
@Configuration
@EnableTransactionManagement(proxyTargetClass=true)
@EnableTransactionManagement(proxyTargetClass = true)
static class SubclassProxyTxConfig {
}
@@ -137,11 +154,6 @@ public class ScheduledAndTransactionalAnnotationIntegrationTests {
@EnableScheduling
static class Config {
@Bean
public PersistenceExceptionTranslationPostProcessor peTranslationPostProcessor() {
return new PersistenceExceptionTranslationPostProcessor();
}
@Bean
public PlatformTransactionManager txManager() {
return new CallCountingTransactionManager();
@@ -151,6 +163,41 @@ public class ScheduledAndTransactionalAnnotationIntegrationTests {
public PersistenceExceptionTranslator peTranslator() {
return mock(PersistenceExceptionTranslator.class);
}
@Bean
public PersistenceExceptionTranslationPostProcessor peTranslationPostProcessor() {
return new PersistenceExceptionTranslationPostProcessor();
}
}
@Configuration
@EnableScheduling
static class AspectConfig {
@Bean
public static AnnotationAwareAspectJAutoProxyCreator autoProxyCreator() {
AnnotationAwareAspectJAutoProxyCreator apc = new AnnotationAwareAspectJAutoProxyCreator();
apc.setProxyTargetClass(true);
return apc;
}
@Bean
public static MyAspect myAspect() {
return new MyAspect();
}
}
@Aspect
public static class MyAspect {
private final AtomicInteger count = new AtomicInteger(0);
@org.aspectj.lang.annotation.Before("execution(* scheduled())")
public void checkTransaction() {
this.count.incrementAndGet();
}
}
@@ -191,6 +238,9 @@ public class ScheduledAndTransactionalAnnotationIntegrationTests {
private final AtomicInteger count = new AtomicInteger(0);
@Autowired(required = false)
private MyAspect myAspect;
@Override
@Transactional
@Scheduled(fixedDelay = 5)
@@ -200,6 +250,9 @@ public class ScheduledAndTransactionalAnnotationIntegrationTests {
@Override
public int getInvocationCount() {
if (this.myAspect != null) {
assertEquals(this.count.get(), this.myAspect.count.get());
}
return this.count.get();
}
}