Restful 服务 Spring 在 Wildfly 上启动 8.x

Restful services with Spring Boot on Wildfly 8.x

我在让一个简单的 hello world 应用程序在 Wildfly 上运行时遇到问题 8.x。我收到的堆栈跟踪是一个空指针异常,获取响应的 headers:

2016-07-15 04:14:28,488 ERROR [org.springframework.boot.context.web.ErrorPageFilter] (default task-4) Forwarding to error page from request [/hello] due to exception [null]: java.lang.NullPointerException
    at java.util.ArrayList.<init>(ArrayList.java:177) [rt.jar:1.8.0_92]
    at io.undertow.servlet.spec.HttpServletResponseImpl.getHeaders(HttpServletResponseImpl.java:248) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
    at javax.servlet.http.HttpServletResponseWrapper.getHeaders(HttpServletResponseWrapper.java:303) [jboss-servlet-api_3.1_spec-1.0.0.Final.jar:1.0.0.Final]
    at org.springframework.http.server.ServletServerHttpResponse$ServletResponseHttpHeaders.get(ServletServerHttpResponse.java:160) [spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.http.server.ServletServerHttpResponse$ServletResponseHttpHeaders.containsKey(ServletServerHttpResponse.java:142) [spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.addContentDispositionHeader(AbstractMessageConverterMethodProcessor.java:346) [spring-webmvc-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:238) [spring-webmvc-4.2.7.RELEASE.jar:4.2.7.RELEASE]

我拼凑了我能想到的最快最简单的 Spring 引导 restful 服务:

package com.tryme;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TrymeController {
    @RequestMapping(value="/hello")
    public ResponseEntity<String> hello()
    {
        return new ResponseEntity<String>("Hello world.", HttpStatus.OK);
    }
}

应用主要是:

package com.tryme;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan
public class TrymeApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {

        SpringApplication.run(TrymeApplication.class, args);

    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(TrymeApplication.class);
    }
}

我阅读了几篇博文,建议如何更改您的 pom 以支持 restful spring 服务,这是我创建的 POM(我尝试使用 3.1 servlet 和 2.5)。

<?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.tryme</groupId>
    <artifactId>tryme</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>tryme</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.6.RELEASE</version>
    </parent>

    <properties>
        <start-class>com.tryme.TrymeApplication</start-class>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--
        <dependency>  
             <groupId>javax.servlet</groupId>  
             <artifactId>servlet-api</artifactId>  
             <version>2.5</version>  
             <scope>provided</scope>
        </dependency>        
         -->
        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-el</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <!--We are building spring boot application with maven-->
    <build>
        <finalName>tryme</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    <!--Repositories for spring libs-->
    <repositories>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>http://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>http://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <!--Repositories for needed plugins -->
    <pluginRepositories>
        <pluginRepository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>http://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>http://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>    
</project>

我尝试在我的 ResponseEntities 上强制 headers,但没有帮助。任何人都可以告诉我是否有什么我可以更改以启动这个简单的应用程序并 运行 Spring 在 8.x Wildfly 上休息?我验证它在 9.x 和 10.x

上工作正常

编辑:这是我最新的 war 的样子。

Undertow < 1.1.0-Final 中存在错误。 Wildfly 8.1 使用 Undertow 1.0.15。

Untertow 1.0.x 中,getHeaders(String) 方法 不会 检查 null.

// from Undertow 1.0.15-final 
// http://grepcode.com/file/repo1.maven.org/maven2/io.undertow/undertow-servlet/1.0.15.Final/io/undertow/servlet/spec/HttpServletResponseImpl.java#HttpServletResponseImpl.getHeaders%28java.lang.String%29
@Override
public Collection<String> getHeaders(final String name) {
    return new ArrayList<String>(exchange.getResponseHeaders().get(name));
}

Undertow 1.1.0 向上 getHeaders(String) 方法检查 null

的 responseHeaders
// from Undertow 1.1.0-final 
// http://grepcode.com/file/repo1.maven.org/maven2/io.undertow/undertow-servlet/1.1.0.Final/io/undertow/servlet/spec/HttpServletResponseImpl.java#HttpServletResponseImpl.getHeader%28java.lang.String%29
@Override
public Collection<String> getHeaders(final String name) {
   HeaderValues headers = exchange.getResponseHeaders().get(name);
    if(headers == null) {
        return Collections.emptySet();
    }
    return new ArrayList<>(headers);
}

遗憾的是我在JBoss / Undertow 问题工具中没有找到相应的错误报告。

所以解决这个问题的唯一方法是修补/覆盖 io.undertow.servlet.spec.HttpServletResponseImpl

用新的更新 modules/system/layers/base/io/undertow/ 中的旧 jar

  • io.undertow.core
  • io.undertow.servlet

你要修改对应​​目录下的module.xml

不确定

  • io.undertow.jsp
  • io.undertow.websocket

对于您的示例,更新核心和 servlet 就足够了。 如果可能,最好升级到最新的 wildly 8.2 版本。

另请参阅关于 JBoss forum

的讨论