首页 > 解决方案 > Spring 引导应用程序无法“自动装配”作为新线程代理的服务类

问题描述

我正在使用Spring Boot[v. 2.1.4.RELEASE] 和@Async注释一起CompletableFuture以实现异步和非阻塞调用。 

我已经实现了一个用于运行TaskExecutor将提供多线程环境的 Config 类,以及一对实现 POST 请求的 Service-Controller 类。

配置

@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {  
    @Bean(name = "musterExecutor")
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(2);
        executor.setQueueCapacity(500);
        executor.setThreadNamePrefix("AppExecutor-");
        executor.initialize();
        return new ThreadPoolTaskExecutor();
    }
}

一个服务类,其中Status是用于映射响应的 pojo。

服务

@Service
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class MusterService<T> {
    private static final String request_status = RestURIConstants.STATUS;
    private static final String request_execution = RestURIConstants.EXECUTE;
    private static final String request_async = Constants.ASYNC;
    private static final String DATA_FUSION = Constants.DATA_FUSION;

@Autowired
private RestTemplate restTemplate;

@Async("musterExecutor")
public CompletableFuture<Status> execute(Payload payload) {
    HttpHeaders headers = setHeaders();
    String input = Constructor.createPayload(payload);
    HttpEntity<String> requestEntity = new HttpEntity<String>(input, headers);
    Status s = restTemplate.postForObject(execution_url, request_execution, Status.class);

    return CompletableFuture.completedFuture(s);
}

@Async("musterExecutor")
public CompletableFuture<Status[]> getStatus() {
    log.debug("Sending Status Request");

    final String status_url = request_status;
    HttpHeaders headers = setHeaders();
    HttpEntity<String> requestEntity = new HttpEntity<String>(request_async, headers);
    Status[] s = restTemplate.postForObject(status_url, requestEntity, Status[].class);

    return CompletableFuture.completedFuture(s);
}

private HttpHeaders setHeaders() {
    // code for setting the Headers
    return headers;
}

}

连同一个简单的

服务接口

public interface GenericService<T> {

    public abstract CompletableFuture<Status[]> getStatus();

    public abstract CompletableFuture<Status> execute(Payload payload);

}

控制器

@RestController
@RequestMapping(path = "/api")
public class MusterController {

    @Autowired
    private MusterService<Status> musterService;


    @RequestMapping(value = "/status", method = RequestMethod.GET)
    @ResponseBody
    public CompletableFuture<Status[]> status() {
        CompletableFuture<Status[]> cf_status = new CompletableFuture<Status[]>();
        try {
            cf_status = musterService.getStatus();
            return cf_status;
        } catch (RestClientException e) {
            e.printStackTrace();
            // TODO: handle exception
        }
        return cf_status;
    }

    @RequestMapping(value = "/execute", method = RequestMethod.POST, produces = "application/json", consumes = "application/json")
    @ResponseBody
    public CompletableFuture<Status> execute(@RequestBody Payload payload) throws SchedulerException, IOException {
        CompletableFuture<Status> cf_execution_body = new CompletableFuture<Status>();
        Status execution_body = new Status();
        try {
            cf_execution_body = musterService.execute(payload);
            execution_body = cf_execution_body.get();
            return cf_execution_body;
        } catch (RestClientException e) {
            log.error("RestClientException:{} \t Cause:{}", e.getMessage(), e.getCause());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        return cf_execution_body;
    }

}

为了启动线程,该类的实例被正确代理,但是当我尝试implement使用接口类(又名public class MusterService<T> implements GenericService<T>..)的服务类时,它给了我以下错误:

引起:org.springframework.beans.factory.BeanNotOfRequiredTypeException
服务被代理为新线程,由于某种原因无法自动装配

当我删除implements然后一切都按预期工作。

注意:我已@EnableAspectJAutoProxy(proxyTargetClass = true) 添加注释以使其按建议工作,但它没有做任何事情。我怎样才能让它工作?

堆栈溢出参考:

标签: javaspring-bootasynchronousspring-aop

解决方案


@EnableAsync导致MusterService被代理,因此它的@Async方法可以是异步的。默认情况下,@EnableAsync如果被代理的类实现单个接口,将创建 JDK 代理。MusterService实现时就是这种情况GenericService。因此,必须将集合服务 bean 作为代理使用,GenericService因为这是代理遵守的合同。

如果您希望您的控制器能够注入一个MusterService实例,您应该修改@EnableAsync为使用 CGLib 代理:

@EnableAsync(proxyTargetClass = true)

推荐阅读