在编写完一个SpringBoot应用后,我们可以将其打包成可执行的Jar包并直接部署到生产环境,这种方式比较简单,也是实际开发中最推荐的部署方式。此外,我们还可以将SpringBoot程序打包成War包,并部署到应用服务器(如Tomcat),下面介绍如何进行这一过程。
首先我们要确保SpringBoot工程的打包方式为Jar,这个<packaging>
属性不指定时其默认值也为Jar,因此我们可以明确指定为Jar或不指定。
<packaging>jar</packaging>
然后我们执行Maven的打包命令。
mvn package
此时我们就可以直接运行得到的Jar包了。
java -jar demo-0.0.1-SNAPSHOT.jar
实际生产环境中,我们通常需要指定很多JVM参数、系统参数等,对于Tomcat部署War包的情况我们都知道可以使用JAVA_OPTS
环境变量指定参数,在Jar包部署的情况下,这些信息可以通过JAVA_TOOL_OPTIONS
环境变量指定。
如果希望打包为War包,首先需要修改Maven的打包方式。
pom.xml
<packaging>war</packaging>
接着,我们还需要对SpringBoot的内嵌Tomcat进行一些配置。
DemoServletInitializer.java
package com.gacfox.bootdemo;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
public class DemoServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
//载入配置类
return builder.sources(DemoApplication.class);
}
}
这个Java类的作用相当于web.xml
,它引入了包含许多配置信息的DemoApplication.class
(实际上许多配置信息都是默认配置或是间接引入的)。
然后我们执行Maven的打包命令。
mvn package
这样我们就得到了一个War包。
这个War包有两种使用方式,一种是将War包复制到Tomcat的webapps
目录即可,但需要注意修改相关的context配置;另外,SpringBoot的War包依然可以像Jar包一样直接启动,我们执行java -jar demo-0.0.1-SNAPSHOT.war
命令即可,这是因为我们得到的War包中仍然包含主函数,打包后的META-INF
中也指定了MAIN-CLASS
等信息,因此可以直接运行。
实际开发中,对于一个采用History路由的前后端分离工程,我们通常采用Nginx进行部署,Nginx会将服务端API反向代理到SpringBoot服务上,而对于前端页面的访问则直接由Nginx提供静态文件,这是通用的做法,下面是一个Nginx的配置例子。
location /api/ {
proxy_pass http://127.0.0.1:8080;
}
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
上面配置中,/api
开头的请求指向后端SpringBoot工程,其它将返回静态文件和主页index.html
,具体页面由前端路由决定。
在某些极特殊情况下,我们需要将前后端工程合并打包(即前端静态资源也由SpringBoot的内置Web服务器提供),实际上这也是可以实现的,一种简单可靠的实现思路就是在SpringBoot服务端手动将前端路由再次指定,让这些路由全部返回前端工程的index.html
即入口页面,下面是具体的配置方法。
首先将前端工程编译,并将构建输出结果黏贴到src/main/resources/static
文件夹内,其次我们需要保证SpringBoot工程引入了spring-boot-starter-thymeleaf
,这是由于为了让SpringBoot工程能够处理HTML页面,我们必须有一个ViewResolver。
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
然后我们配置application.properties
,让SpringBoot能正确找到前端工程生成的index.html
和其它静态资源。
application.properties
spring.thymeleaf.prefix=classpath:/static/
spring.web.resources.static-locations=classpath:/static/
spring.mvc.static-path-pattern=/**
最后我们还需要添加一个Controller,将所有的前端路由指向index
这个视图。
IndexController.java
package com.gacfox.demo.aio.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class IndexController {
@RequestMapping(value = {"/", "/docs"}, method = RequestMethod.GET)
public String index() {
return "index";
}
}
此时我们就可以将SpringBoot工程构建,得到一个前后端工程合并部署的Jar包(或War包)了。
注意:一般来说,我们都应该使用Nginx或类似的支持反向代理的静态服务器部署前后端分离项目,这是一种最佳实践。合并打包有诸多缺点,比如静态文件由Tomcat提供,这会影响应用服务器并发性能和吞吐量,此外前端工程无法单独更新也不利于版本发布和灰度发布。合并打包仅适用于极特殊场景,例如少数全栈开发者的小型项目或个人独立项目,此时合并打包的产物只有一个Jar包,方便部署;此外还适用于交付非专业用户,用户不会用Nginx或是不理解、拒不提供Nginx的情况,不得不为他们进行合并打包。