2016-11-14 2 views
4

Следующая конечная точка REST, показанная ниже, работает так, как ожидается, когда приложение SpringBoot запускается из исполняемого JAR. То есть, он возвращает клиенту текст «Мой тестовый ответ». Тем не менее, когда я упаковываю то же приложение, что и WAR, и развертываю его в Tomcat (8.0.29), он выдает следующее исключение:Как включить поддержку async в приложении Springboot, упакованном и развернутом как WAR

Произошла непредвиденная ошибка (тип = Внутренняя ошибка сервера, статус = 500). Поддержка Async должна быть включена на сервлете и для всех фильтров, участвующих в обработке запроса async. Это делается в Java-коде с использованием API-интерфейса Servlet или добавлением «true» в объявления сервлетов и фильтров в web.xml.

package my.rest.controllers; 

import java.io.ByteArrayInputStream; 
import java.io.InputStream; 
import java.io.OutputStream; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RequestMethod; 
import org.springframework.web.bind.annotation.RestController; 

import javax.servlet.http.HttpServletResponse; 
import org.springframework.web.bind.annotation.ResponseBody; 
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; 

@RestController 
@RequestMapping("/api/file") 
public class FileContentRestController { 

static final int BUFFER = 2048; 

@RequestMapping(value = "/content", method = RequestMethod.GET) 
@ResponseBody 
public StreamingResponseBody getFileContent(HttpServletResponse response) { 
    response.setContentType("text/plain"); 
    response.setCharacterEncoding("UTF-8"); 

     final InputStream portalFileStream = new ByteArrayInputStream("My test response".getBytes()); 
     return (OutputStream outputStream) -> { 
      int n; 
      byte[] buffer = new byte[1024]; 
      while ((n = portalFileStream.read(buffer)) > -1) { 
       outputStream.write(buffer, 0, n); 
      } 
      portalFileStream.close(); 
     }; 

} 

} 

Мое понимание от here и в других местах, что SpringBoot обеспечивает поддержку асинхронной всех фильтров и сервлетов зарегистрированных SpringBoot. Вероятно, это будет случай, когда вы запускаете автономный JAR со встроенным контейнером Tomcat.

Как я могу обеспечить поддержку async при развертывании в качестве WAR?

Мое приложение SpringBoot настроен таким образом:

package my; 

import com.fasterxml.jackson.core.JsonProcessingException; 
import org.springframework.boot.Banner; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 
import org.springframework.boot.builder.SpringApplicationBuilder; 
import org.springframework.boot.web.support.SpringBootServletInitializer; 
import org.springframework.scheduling.annotation.EnableAsync; 

@SpringBootApplication 
@EnableAsync 
public class MyRestApp extends SpringBootServletInitializer { 

    @Override 
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { 
     return configureApplication(builder); 
    } 

    public static void main(String[] args) throws JsonProcessingException { 
     configureApplication(new SpringApplicationBuilder()).run(args); 
    } 

    private static SpringApplicationBuilder configureApplication(SpringApplicationBuilder builder) { 
     return builder.sources(MyRestApp.class).bannerMode(Banner.Mode.OFF); 
    } 

} 

с MVC сконфигурирован таким образом:

package my; 

import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.core.task.AsyncTaskExecutor; 
import org.springframework.scheduling.annotation.EnableAsync; 
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer; 
import org.springframework.web.servlet.config.annotation.CorsRegistry; 
import org.springframework.web.servlet.config.annotation.EnableWebMvc; 
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 

@Configuration 
@EnableWebMvc 
@EnableAsync 
public class MyMvcConfiguration extends WebMvcConfigurerAdapter { 

    @Override 
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) { 
     configurer.setDefaultTimeout(-1); 
     configurer.setTaskExecutor(asyncTaskExecutor()); 
    } 

    @Bean 
    public AsyncTaskExecutor asyncTaskExecutor() { 
     ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 
     executor.setCorePoolSize(2); 
     executor.setMaxPoolSize(2); 
     executor.setQueueCapacity(500); 
     executor.setThreadNamePrefix("SpringAsyncThread-"); 
     executor.initialize(); 
     return executor; 
    } 

    @Bean 
    public WebMvcConfigurer corsConfigurer() { 
     return new WebMvcConfigurerAdapter() { 
      @Override 
      public void addCorsMappings(CorsRegistry registry) { 
       registry.addMapping("/**") 
         .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"); 
      } 
     }; 
    } 

} 

Наконец, приложение построен и упаковывают с использованием Maven со следующим POM:

<?xml version="1.0" encoding="UTF-8"?> 
<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/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>com.acme</groupId> 
    <artifactId>my-rest-app</artifactId> 
    <version>1.0.0-SNAPSHOT</version> 
    <packaging>war</packaging> 
    <name>my-rest-app</name> 
    <description></description> 
    <parent> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter-parent</artifactId> 
     <version>1.4.1.RELEASE</version> 
     <relativePath/> <!-- lookup parent from repository --> 
    </parent> 
    <properties> 
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
     <java.version>1.8</java.version> 
    </properties> 
    <dependencies> 
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-web</artifactId> 
     </dependency>  
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-tomcat</artifactId> 
      <scope>provided</scope> 
     </dependency> 
    </dependencies> 
    <build> 
     <resources> 
      <resource> 
       <directory>${project.basedir}/src/main/resources</directory> 
      </resource> 
      <resource> 
       <directory>${project.build.directory}/generated-resources</directory> 
      </resource> 
     </resources> 
     <plugins> 
      <plugin> 
       <groupId>org.springframework.boot</groupId> 
       <artifactId>spring-boot-maven-plugin</artifactId> 
      </plugin> 
     </plugins> 
    </build> 
</project> 

ответ

3

Ну, исключение, которое вы разобрали, говорит все:

Произошла непредвиденная ошибка (тип = Внутренняя ошибка сервера, статус = 500). Поддержка Async должна быть включена на сервлете и для всех фильтров, участвующих в обработке асинхронных запросов. Это делается в Java-коде с использованием API-интерфейса Servlet или добавлением «true» в объявления сервлетов и фильтров в web.xml.

Таким образом, вам нужно включить его либо в свой web.xml, либо (и потому, что вы используете приложение для загрузки весны) вам нужно настроить конкретный компонент.

Может быть, этот фрагмент кода для AppConfig поможет

@Bean 
public ServletRegistrationBean dispatcherServlet() { 
    ServletRegistrationBean registration = new ServletRegistrationBean(new DispatcherServlet(), "/"); 
    registration.setAsyncSupported(true); 
    return registration; 
} 
+1

Приложение 'springboot', вероятно, не имеет файла' web.xml' – pleft

+0

Jep, только что отредактировал мой ответ – smsnheck

+1

Что это значит сделать, это создать сервлет диспетчера, настроенный с внешним XML-файлом, поэтому я получаю: java.io. FileNotFoundException: Не удалось открыть ресурс ServletContext [/WEB-INF/dispatcherServlet-servlet.xml] . –

0

У меня была такая же проблема. Запуск приложения на встроенном сервере tomcat (с maven-tomcat7-plugin) отлично работает, без ошибок. Развернуто на внешний сервер tomcat (приложение загрузки весны в формате .WAR):

Произошла непредвиденная ошибка (тип = Внутренняя ошибка сервера, статус = 500). Поддержка Async должна быть включена на сервлете и для всех фильтров, участвующих в обработке асинхронных запросов. Это делается в Java-коде с использованием API-интерфейса Servlet или добавлением «true» в объявления сервлетов и фильтров в web.xml.

Это единственное решение, которое сработало для меня. Мне пришлось создать файл src/main/webapp/WEB-INF/web.xml со следующим содержанием:

<?xml version="1.0" encoding="UTF-8"?> 
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 
     version="3.0" metadata-complete="true"> 

    <filter> 
      <filter-name>cacheControlFilter</filter-name> 
      <filter-class>xxx.yourimplementation.CacheControlFilter</filter-class> 
      <async-supported>true</async-supported> 
      <init-param> 
       <param-name>css,html,js</param-name> 
       <param-value>cache-control=1800,edge-control=1800</param-value> 
      </init-param> 
      <init-param> 
       <param-name>ajax,htm</param-name> 
       <param-value>cache-control=0,edge-control=0</param-value> 
      </init-param> 
      <init-param> 
       <param-name>doc,gif,ico,jpe,jpeg,jpg,pdf,png,swf</param-name> 
       <param-value>cache-control=1800,edge-control=7200</param-value> 
      </init-param> 
    </filter> 

</webapp> 

Это исправило проблему для меня. Надеюсь, поможет!

0

У меня была такая же проблема в моем приложении springboot.

Async support must be enabled on a servlet and for all filters involved in async...... 

Я просто добавить

@WebFilter (asyncSupported = истина)

в моих фильтров. По умолчанию является ложным:

/**
* Объявляет поддерживает ли фильтр асинхронный режим работы. *
* @see javax.servlet.ServletRequest # startAsync * @see javax.servlet.ServletRequest # startAsync (ServletRequest, * ServletResponse) */
булево asyncSupported() по умолчанию ложь;

0

Мой внешний экземпляр Tomcat был установлен и настроен с помощью NetBeans. В папке% CATALINA_BASE% \ conf есть web.xml, который применяется ко всем приложениям, развернутым на сервере. В нем был фильтр с именем HTTPMonitorFilter, который не поддерживал асинхронные запросы. Добавление true к этому определению фильтра решило мою проблему.

Смежные вопросы