0%

How to deploy spring boot application to sap cloud platform neo

普通Spring Boot程序的部署

传统的spring boot web程序,其pom.xml和main函数所在的class通常是这样的。
以spring boot guide提到的程序为例,通常只需要在pom中这样写就可以让程序正常执行了

1
2
3
4
5
6
7
8
9
10
11
12
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
</parent>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

Spring Boot自带的tomcat容器,可以让程序无需依赖外面的容器,实现更好与外部环境的松耦合。
在诸如cloud foundry之类的环境里可以无障碍运行,但是在sap cloud platform neo环境中,
部署后的程序却总是无法正常运行,显示为404 not found。

怎样将Spring Boot程序部署在Neo上

查来查去在网上找到了sap自己给出的sample,比对了半天发现问题出在pom.xml和main函数的写法上。
spring-boot-getting-started

SAP给出的guide上明确的写着,

  1. pom.xml要写成这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<dependencies>
<!-- developer tools for hot code-replacement etc. -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>

<!--Embedded tomcat etc. -->
<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>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>

因为SAP Cloud Platform的Neo环境中内置了Tomcat容器,所以当部署到Neo上去的时候,你的程序就不应该再内嵌tomcat了。

tomcat使用部署环境提供的tomcat,写成provided。而且Neo中也内置了logging的库,所以相应的依赖也应该写成provided

  1. main函数要写成这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application extends SpringBootServletInitializer
{

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

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

原因

通过查看官方的文档,明白了为什么main函数要写成上面的样子。
How to traditional-deployment
官方文档中提到,

The first step in producing a deployable war file is to provide a SpringBootServletInitializer subclass and override its configure method. Doing so makes use of Spring Framework’s Servlet 3.0 support and lets you configure your application when it is launched by the servlet container. Typically, you should update your application’s main class to extend SpringBootServletInitializer.

翻译成中文就是,如果你想让你的程序运行在servlet容器(比如Neo中内嵌的Tomcat),你就需要让你的main函数继承SpringBootServletInitializer并重写其中的configure方法。
普通的Spring Boot程序不需要这么写,是因为它们不需要运行在外置的servlet容器中。