Spring启动mvc异步执行

时间:2016-12-27 19:09:24

标签: java rest spring-mvc asynchronous spring-boot

我尝试使用java.util.concurrent.Callable执行最简单的异步REST控制器:

@RequestMapping("/AsyncRequest")
public Callable asyncRequest() {
    return () -> {
        Thread.sleep(3000);
        return "reply";
    };
}

然后我在浏览器中运行http://localhost/AsyncRequest两次。 我得到的第一个答案是3秒钟,但第二个答案是在6秒钟后。 似乎请求不是异步处理的。 为什么会这样?

1 个答案:

答案 0 :(得分:3)

Spring Boot行为实际上取决于版本和配置。

以下配置和代码适用于我:

<强>简化版

package com.stackoverflow.spring.boot.async;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Import;

@Import(WebConfig.class)
@SpringBootApplication
public class WebMain {
  private final SpringApplication application;

  public WebMain() {
    final SpringApplicationBuilder applicationBuilder = new SpringApplicationBuilder(WebMain.class);
    application = applicationBuilder.build();
  }

  public SpringApplication getApplication() { return application; }

  public static void main(final String[] args) {
    new WebMain().getApplication().run(args);
  }
}

<强>配置

package com.stackoverflow.spring.boot.async;


import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter implements EmbeddedServletContainerCustomizer
{
  public void customize(final ConfigurableEmbeddedServletContainer container) {}
}

<强>控制器

我已将睡眠时间改为6秒,并将一些有效负载添加到响应中。

package com.stackoverflow.spring.boot.async;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Date;
import java.util.concurrent.Callable;

@Controller
public class AsyncController {
  @RequestMapping(path = "/AsyncRequest", method = RequestMethod.GET)
  @ResponseBody
  public Callable<String> asyncRequest() {
    return () -> {
      final long currentThread = Thread.currentThread().getId();
      final Date requestProcessingStarted = new Date();

      Thread.sleep(6000L);

      final Date requestProcessingFinished = new Date();

      return String.format(
          "request: [threadId: %s, started: %s - finished: %s]"
          , currentThread, requestProcessingStarted, requestProcessingFinished);
    };
  }
}

<强>的pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

      <modelVersion>4.0.0</modelVersion>

      <groupId>com.stackoverflow.spring.boot</groupId>
      <artifactId>async</artifactId>
      <packaging>jar</packaging>
      <version>1.0-SNAPSHOT</version>

      <properties>
        <java.version>1.8</java.version>
        <spring-boot.version>1.4.1.RELEASE</spring-boot.version>
      </properties>

      <dependencies>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-dependencies</artifactId>
          <version>${spring-boot.version}</version>
          <type>pom</type>
          <scope>import</scope>
        </dependency>

        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot</artifactId>
          <version>${spring-boot.version}</version>
        </dependency>

        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
          <version>${spring-boot.version}</version>
        </dependency>

        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-actuator</artifactId>
          <version>${spring-boot.version}</version>
        </dependency>
      </dependencies>

      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <inherited>true</inherited>
            <configuration>
              <source>${java.version}</source>
              <target>${java.version}</target>
            </configuration>
          </plugin>

          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>${spring-boot.version}</version>
            <executions>
              <execution>
                <goals>
                  <goal>repackage</goal>
                </goals>
                <configuration>
                  <classifier>exec</classifier>
                </configuration>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>

    </project>

<强>测试

java -version
java version "1.8.0_111"
Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)

--
mvn spring-boot:run
...
--
# start following command from different consoles:
curl http://localhost:8080/AsyncRequest

<强>结果

request: [threadId: 33, started: 15:50:28 - finished: 15:50:34]
request: [threadId: 35, started: 15:50:29 - finished: 15:50:35]
request: [threadId: 37, started: 15:50:30 - finished: 15:50:36]