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);
}
}