如何在打包并部署为WAR的Springboot应用程序中启用异步支持

问题描述 投票:4回答:5

当我的SpringBoot应用程序从可执行JAR运行时,下面显示的以下REST端点按预期工作。也就是说,它将文本“我的测试响应”返回给客户端。但是,当我将相同的应用程序打包为WAR并部署到Tomcat(8.0.29)时,它会抛出以下异常:

出现意外错误(type = Internal Server Error,status = 500)。必须在servlet和异步请求处理中涉及的所有过滤器上启用异步支持。这是使用Servlet API在Java代码中完成的,或者在web.xml中向servlet和过滤器声明添加“true”。

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注册的所有过滤器和servlet的异步支持。当从具有嵌入式Tomcat容器的独立JAR运行时,情况肯定会出现这种情况。

如何在部署为WAR时确保启用异步支持?

我的Spring Boot应用程序配置如下:

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>
java spring-boot war servlet-3.0
5个回答
3
投票

那么你解析的异常就说明了一切:

出现意外错误(type = Internal Server Error,status = 500)。必须在servlet和异步请求处理中涉及的所有过滤器上启用异步支持。这是使用Servlet API在Java代码中完成的,或者在web.xml中向servlet和过滤器声明添加“true”。

因此,您需要在web.xml中启用它或(因为您使用的是spring-boot应用程序),您必须配置特定的bean。

也许这个AppConfig的代码片段会有所帮助

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

1
投票

我有同样的问题。在嵌入式tomcat服务器(使用maven-tomcat7-plugin)中运行应用程序工作正常,没有错误。部署到外部tomcat服务器(打包为.WAR的spring boot app):

出现意外错误(type = Internal Server Error,status = 500)。必须在servlet和异步请求处理中涉及的所有过滤器上启用异步支持。这是使用Servlet API在Java代码中完成的,或者在web.xml中向servlet和过滤器声明添加“true”。

这是唯一对我有用的解决方案。我必须使用以下内容创建文件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
投票

我在春季启动应用程序中遇到了同样的问题。

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
投票

使用Spring引导SimpleBeanPropertyFilter来解决它使用下面的链接来查找git repo并获得一个想法可能会有所帮助 Git Repo

© www.soinside.com 2019 - 2024. All rights reserved.