SpringBoot @Async加在实现接口类的非接口方法上获取Bean异常

一、场景复现

报错日志

***************************
APPLICATION FAILED TO START
***************************

Description:

A component required a bean of type 'com.mk.service.TestService' that could not be found.


Action:

Consider defining a bean of type 'com.mk.service.TestService' in your configuration
@Service
public class TestService implements ITestService{
    
    @Async
    public Future<String> doActionAsync(){
        
        return new AsyncResult(doAction());
    }

    @Override
    public String doAction() {
        
        return "done";
    }
}

public interface ITestService {
    
    String doAction();
}

@Component
public class Runner implements ApplicationContextAware {

    @EventListener(ApplicationReadyEvent.class)
    public void run(){

        TestService testService = applicationContext.getBean(TestService.class);
        testService.doActionAsync();
    }

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext =applicationContext;
    }
}

@EnableAsync
@Configuration
@SpringBootApplication
public class ServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceApplication.class, args);
    }

}

二、分析原因

(1)doActionAsync加上接口方法,执行一样报错

@Service
public class TestService implements ITestService{

    @Override
    @Async
    public Future<String> doActionAsync(){

        return new AsyncResult(doAction());
    }

    @Override
    public String doAction() {

        return "done";
    }
}

(2)使用ITestService调用就不报错

@Component
public class Runner implements ApplicationContextAware {

    @EventListener(ApplicationReadyEvent.class)
    public void run(){

        ITestService testService = applicationContext.getBean(ITestService.class);
        testService.doActionAsync();
    }

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext =applicationContext;
    }
}

(3)Springboot 代理类型

Springboot 默认代理类型为jdk proxy

bean有实现接口使用jdk proxy代理,没有实现接口则使用cglib代理

 

三、解决方案

(1)将方法抽象到接口

(2)强制使用cglib代理

@EnableAsync(proxyTargetClass = true)
@Configuration
@SpringBootApplication
public class ServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceApplication.class, args);
    }

}