Affects: 5.3.3
I have a @Bean
class with a public method "void schedule()", that is annotated with both @Async
and @Scheduled
; the class also implements an interface, while the "schedule()" method is not part of that interface.
The @Configuration
class for this testcase is also annotated with all of the following: @EnableAsync
, @EnableScheduling
and @EnableAspectJAutoProxy(proxyTargetClass = true)
.
Spring complains however with the following exception :
IllegalStateException: Need to invoke method 'schedule' declared on target class 'TestBean', but not found in any interface(s) of the exposed proxy type. Either pull the method up to an interface or switch to CGLIB proxies by enforcing proxy-target-class mode in your configuration.
I can only get the testcase to succeed by adding the "schedule()" method to the interface even though I shouldn't have to because I've already used @EnableAspectJAutoProxy(proxyTargetClass = true)
.
(Other not really feasible options for getting the testcase to work include not letting the bean implement the interface, or removing all methods from the interface).
Here is the full source for the testcase:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* This test will fail even though there is already a @EnableAspectJAutoProxy(proxyTargetClass = true) on
* the TestConfiguration class, with the following error:
*
* "WARN GenericApplicationContext:596 - Exception encountered during context initialization - cancelling
* refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name
* 'testBean' defined in SchedulingTest$TestConfiguration: Initialization of bean failed; nested exception
* is java.lang.IllegalStateException: Need to invoke method 'schedule' declared on target class 'TestBean',
* but not found in any interface(s) of the exposed proxy type. Either pull the method up to an interface
* or switch to CGLIB proxies by enforcing proxy-target-class mode in your configuration."
*
* Commenting either *one* of the lines marked with (1), (2), or (3) will make the test succeed.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SchedulingTest.TestConfiguration.class)
public class SchedulingTest {
@Configuration
@EnableAsync
@EnableScheduling
@EnableAspectJAutoProxy(proxyTargetClass = true)
static class TestConfiguration {
@Bean
public TestBean testBean() {
return new TestBean();
}
@Bean
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
return new ThreadPoolTaskExecutor();
}
}
interface TestInterface {
// void schedule(); // (1) uncommenting this method will make the test succeed
void execute(); // (2) commenting this method will make the test succeed
}
static class TestBean
implements TestInterface // (3) commenting this implements clause will make the test succeed
{
@Async
@Scheduled(cron = "*/5 * * * * *")
public void schedule() {
System.out.println("In schedule method");
}
public void execute() {
}
}
@Test
public void testIt() throws InterruptedException {
Thread.sleep(6000);
}
}
Comment From: mdeinum
The @EnableAsync
also has proxyTargetClass
which needs to be set to true
, this will enable class-based proxies for @Async
methods. The proxyTargetClass
of @EnableAspectJAutoProxy
doesn't change that behaviour. If you remove @EnableAspectJAutoProxy
the test will fail with the same error.
Comment From: florimon
Thanks, I didn't expect an answer so soon :) It never occurred to me to dig into the @EnableAsync
annotation. Guess I was set on the wrong foot by the error message and until now only having had to fiddle with setting the proxyTargetClass on the EnableAspectJAutoProxy. Thanks again, ok to close this one!
Comment From: mdeinum
you might want to keep it open for now. I can imagine that it might be used to make it easier (or add documentation) on how to enable class proxies.
Comment From: jamesdh
Just bumped into this after fixing some @Scheduled
beans that weren't correctly using @Async
! Very difficult to find this solution via google but thankful for the answer @mdeinum!
Comment From: snicoll
Spring Boot does it consistently and offer an option to switch from one to the other. I am afraid at the framework level, the proxy strategies are fairly isolated as these are independent building blocks.