Spring 引导的异步服务

Asynchronous service with Spring boot

我正在尝试 运行 使用 springboot 的基本异步服务。
调用请求时出现异常。不知道为什么会这样,我已经使用了 oracle 网站和 jersey 网站上的所有说明和代码片段。我在这里遗漏了什么吗? 如果您需要更多信息,请问我,我会相应地更新问题。谢谢你。

org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.ws.rs.container.AsyncResponse]: Specified class is an interface
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:101)
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.createAttribute(ModelAttributeMethodProcessor.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.createAttribute(ServletModelAttributeMethodProcessor.java:80)
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:106)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:78)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:129)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:775)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:858)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:217)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)

pom 中的依赖项

    <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>info.cukes</groupId>
        <artifactId>cucumber-junit</artifactId>
        <version>1.1.7</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.bundles.repackaged</groupId>
        <artifactId>jersey-guava</artifactId>
        <version>2.22.1</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-common</artifactId>
        <version>2.22.1</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-client</artifactId>
        <version>2.22.1</version>
    </dependency>
    <dependency>
        <groupId>info.cukes</groupId>
        <artifactId>cucumber-picocontainer</artifactId>
        <version>1.1.7</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>info.cukes</groupId>
        <artifactId>cucumber-spring</artifactId>
        <version>1.2.4</version>
    </dependency>
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-chrome-driver</artifactId>
        <version>2.42.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.4</version>
    </dependency>
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>9.3-1100-jdbc41</version>
    </dependency>
    <dependency>
        <groupId>org.dbunit</groupId>
        <artifactId>dbunit</artifactId>
        <version>2.4.8</version>
        <type>jar</type>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.github.springtestdbunit</groupId>
        <artifactId>spring-test-dbunit</artifactId>
        <version>1.1.0</version>
    </dependency>
    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-core-asl</artifactId>
        <version>1.9.13</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>javax.ws.rs</groupId>
        <artifactId>javax.ws.rs-api</artifactId>
        <version>2.0</version>
    </dependency>

控制器 class

@RestController
@RequestMapping(value = "backend-service")
public class AsynchronousController {

private static int timeout = 50;

public static void setTimeout(int seconds) {
    timeout = seconds;
}

private static int numberOfSuccessResponses = 0;
private static int numberOfFailures = 0;
private static Throwable lastException = null;

@RequestMapping(method = GET, value = "method")
public void asyncGet(@Suspended final AsyncResponse asyncResponse) {
    asyncResponse.setTimeoutHandler(asyncResponse1 -> asyncResponse1.resume(status(SERVICE_UNAVAILABLE)
            .entity("Operation time out.").build()));
    asyncResponse.setTimeout(timeout, SECONDS);

    asyncResponse.register((CompletionCallback) throwable -> {
        if (throwable == null) {
            // (response already written to the client)
            numberOfSuccessResponses++;
        } else {
            numberOfFailures++;
            lastException = throwable;
        }
    });

    new Thread(new Runnable() {
        @Override
        public void run() {
            String result = veryExpensiveOperation();
            asyncResponse.resume(result);
        }

        private String veryExpensiveOperation() {
            JSONObject json = new JSONObject();
            try {
                json.put("timestamp", new Date(System.currentTimeMillis()));
                json.put("response", newHashMap());
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (JSONException e) {
                e.printStackTrace();
            }
            // todo check if json is returned
            return json.toString();
        }
    }).start();
  }
}

Spring 默认情况下,引导使用 SpringMVC 服务(您配置使用的)但是由于这种混淆,您正试图混合使用 Jax-RS 我只是将回答如何以 Spring MVC 方式执行此操作。

我是凭记忆写的,所以如果我有什么笨手笨脚的,请告诉我

您的配置 class 应该有 @EnableAsync

@SpringBootApplication
@EnableAsync
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
} 

这是你的控制器

@RestController
public class MyController {
    @Autowired
    MyService myService;

    //DeferredResult does not send a response until .setResult or setErrorResult is called
    public DeferredResult<String> myService() {
        DeferredResult<String> result = new DeferredResult<>();
        //I'm using Java8 lambda for brevity use an anonymous class instead if using less than java8
        myService.asyncLongOperation((operationResult) -> result.setResult(operationResult))
        return result;
    }
}

我认为@Async 需要在不同的 class 中才能正常工作,但请随时挑战我的假设并将此方法保留在 MyController

@Service
public class MyService {
    @Async //This annotation replaces building your own thread
    public void asyncLongOperation(Consumer<String> consumer) {
        String pie = calculatePieWhichIsShorterThanPi();
        consumer.accept(pie);
    }
}

参考 异步 - https://spring.io/guides/gs/async-method/

DeferredResult - https://spring.io/blog/2012/05/07/spring-mvc-3-2-preview-introducing-servlet-3-async-support