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.