Comment mettre en œuvre un asynchrone RESTE demande à un contrôleur à l'aide Springboot?

Je suis en train de mettre en œuvre un contrôleur asynchrone à l'aide de SprintBoot. Je veux faire REPOSER demande à un contrôleur de sorte que le contrôleur retourne immédiatement, tandis que le travail se poursuit sur le serveur.

Je suis en suivant ce Printemps, exemple: http://spring.io/blog/2012/05/07/spring-mvc-3-2-preview-introducing-servlet-3-async-support

Je suppose que c'est un problème de configuration. Quelqu'un peut-il me dire ce que je suis absent? Je suis nouveau sur le Printemps donc si vous pouviez s'il vous plaît fournir autant de détails que possible, il serait appréciée.

À l'aide d'un travail de contrôleur j'ai fait les modifications suivantes:

//Before
@RequestMapping(method=RequestMethod.POST)
public String processUpload(final MultipartFile file) {
    //...
    return "someView";
}

//After
@RequestMapping(method=RequestMethod.POST)
public Callable<String> processUpload(final MultipartFile file) {

  return new Callable<String>() {
    public Object call() throws Exception {
      //...
      return "someView";
    }
  };
}

Je suis en mesure d'appeler le nouveau contrôleur, mais j'ai deux questions ci-dessous:

  1. Le nouveau contrôleur n'est pas appelée de façon asynchrone. Le navigateur se bloque lors de l'appel. L'appel n'exécuter le code.
  2. La demande arrive à sortir avec cette erreur:

    2015-03-06 16:36:10.592 ERREUR 13012 --- [ MvcAsync1] o.s.w.c.demande.async.WebAsyncManager : n'a pas Pu terminer async traitement en raison de dépassement de délai ou d'une erreur de réseau

Mise à jour:
J'ai été en mesure de résoudre le délai d'expiration par la création de la suite de haricots dans mon dossier de candidature:

@Bean
public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
        factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {

            @Override
            public void customize(Connector connector) {

                connector.setPort(9000);
                connector.setAsyncTimeout(60000);
            }
        });
        return factory;
    }

Mais l'appel de l'au contrôleur n'est pas encore asynchrone. Le navigateur se bloque toujours pour la durée de l'appel.

Je suis toujours à la recherche de l'aide sur la façon de faire l'appel RESTE pour le contrôleur de retourner immédiatement tout en faisant le travail en arrière-plan.

Mise à jour II

Merci Dave. J'ai tenté de mettre en œuvre une méthode asynchrone dans un haricot.

Voici ma classe d'application:

@SpringBootApplication
@EnableAsync
public class Application {

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

    @Bean
    public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
        factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {

            @Override
            public void customize(Connector connector) {

                connector.setPort(9000);
                connector.setAsyncTimeout(60000);
            }
        });
        return factory;
    }
 }

Voici mon haricot classe:

public class LongProcess {

    @Async
    public Future<String> call() {
        try {
            System.out.println("Sleeping now...");
            Thread.sleep(10000);
            return new AsyncResult<String>("Hey");
        } catch (InterruptedException e) {
            //TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
    }

}

Ma classe de configuration:

@Configuration
@EnableAsync
public class LongProcessConfiguration implements AsyncConfigurer {

    @Bean
    public LongProcess longProcessBean() {
        return new LongProcess();
    }

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setMaxPoolSize(10);
        taskExecutor.setThreadNamePrefix("LULExecutor-");
        taskExecutor.initialize();
        return taskExecutor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new SimpleAsyncUncaughtExceptionHandler();
    }

}

Ma méthode de contrôleur:

@RequestMapping("/utilities/longProcess")
    public String longProcess() {

        System.out.println("Starting long process...");
        CsvFileDifferConfiguration context = new CsvFileDifferConfiguration();
        LongProcess process = context.longProcessBean();
        Future<String> result = process.call();
        System.out.println("Done!");
        return "{success: 1}";

    }

Ce qui malheureusement n'est toujours pas de retour immédiatement. Notez que je n'ai pas de soins sur le résultat de LongProcess. La méthode est appelée avec succès, mais pas dans le fond. Toute idée de ce que je pourrais être absent?

Comme un test, si je change la méthode de contrôleur attendre le résultat, le temps d'attente du bloc n'est jamais entré:

@RequestMapping("/utilities/longProcess")
    public String longProcess() throws InterruptedException {

        System.out.println("Starting long process...");
        CsvFileDifferConfiguration context = new CsvFileDifferConfiguration();
        LongProcess process = context.longProcessBean();
        Future<String> result = process.call();
        while (!(result.isDone())) {
            Thread.sleep(1); //10-millisecond pause between each check
            System.out.println("Waiting for Long Process...");
        }
        System.out.println("Done!");
        return "{success: 1}";

    }

Mise à jour III

J'ai remplacé

CsvFileDifferConfiguration context = new CsvFileDifferConfiguration();
            LongProcess process = context.longProcessBean();

avec

@Autowired
private LongProcess process;

et cela a résolu le problème.

OriginalL'auteur Matthew S | 2015-03-06