How to enable async support in a Springboot application packaged and deployed as a WAR

The following REST endpoint, shown below, works properly when my SpringBoot application starts from an executable JAR file. That is, it returns the text "My test answer" to the client. However, when I package the same application as WAR and deploy to Tomcat (8.0.29), it throws the following exception:

An unexpected error has occurred (type = Internal server error, status = 500). Asynchronous support must be enabled on the servlet and for all filters involved in processing asynchronous requests. This is done in Java code using the Servlet API or by adding "true" to the servlet and filtering the ads in 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();
        };

}

}

, SpringBoot , SpringBoot. , , JAR Tomcat.

, 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>
+5
5

, , :

( = , = 500). Async , . Java- API- Servlet "true" web.xml.

, web.xml, ( , spring -boot) bean.

, AppConfig

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

. tomcat ( maven-tomcat7-plugin) , . tomcat ( spring, .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>

. , !

+1

springboot.

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

@WebFilter (asyncSupported = true)

. false:

/**
     * , .      *
     * @see javax.servlet.ServletRequest # startAsync      * @see javax.servlet.ServletRequest # startAsync (ServletRequest,      * ServletResponse)      */
     boolean asyncSupported() false;

+1

Tomcat NetBeans. % CATALINA_BASE%\conf web.xml, , . HTTPMonitorFilter, . true .

+1

SimpleBeanPropertyFilter, , git-

-1

Source: https://habr.com/ru/post/1660696/


All Articles