将Maven项目发布到新服务器的核心方法是:在本机执行mvn clean package打包,通过scp或rsync上传产物,在服务器上安装JDK与Maven环境,用systemd托管进程,最后用Nginx反向代理并校验端口连通性。这套流程覆盖了从环境准备到灰度上线的完整闭环,也是目前中小团队最常用的部署路径,下面按实际操作顺序拆解,每一步都给出可直接复制的命令和避坑要点。
部署前必须确认的三件事
新服务器的初始状态往往千差万别,动手前先花十分钟核对硬性条件,能避开后续大量返工。
服务器操作系统与CPU架构的匹配
先确认系统版本,执行cat /etc/os-release查看发行版信息,CentOS 7和Ubuntu 22.04的包管理命令完全不同,后续安装JDK和Maven时需要选择对应版本,同时检查架构:
x86_64对应常规的Linux x64版本aarch64需要下载ARM架构专用的JDK压缩包
行业共识认为,约七成的新服务器都是x86_64架构,但对ARM实例(如华为云鲲鹏、AWS Graviton)而言,用错JDK版本会导致启动时报Exec format error,这个坑相当普遍。
JDK版本与Maven项目编译级别的兼容性
新版Spring Boot 3.x强制要求JDK 17+,而你本机若用JDK 11打包,到了服务器上装的是JDK 8,项目会直接启动失败,确认项目用的Java版本,用java -version和mvn -version检查本机环境,然后在服务器上安装完全一致的版本,最简单的判断方法是看项目根目录pom.xml里<java.version>标签的值。
数据库与中间件的地址预登记
新服务器上项目启动时,application.yml里通常写着数据库、Redis、MQ的连接地址,提前确认这些中间件是否也在新环境,或者继续指向旧服务器的内网IP,这一步容易让人疏忽且很折磨人项目明明起来了,却连不上数据库,日志还只报一句Connection refused。
服务器环境安装的两种实用方案
装JDK和Maven是绕不开的第一步,这里给出两条不同路径,分别对应有外网和无外网的场景。
包管理器快速安装(适合有外网环境)
Ubuntu/Debian系执行:
apt update
apt install openjdk-17-jdk maven -y
CentOS/RHEL系执行:
yum install java-17-openjdk-devel maven -y
装完验证一下:java -version和mvn -v,能正确输出版本号即可,这种方式胜在省心,缺点是版本可能不是最新的,但部署生产项目完全够用。
离线解压部署(适合内网隔离环境)
许多政务云和金融内网不允许直接访问公网仓库,这时候需要在自己电脑上提前下载好如下压缩包:
- JDK:从Adoptium官网下载
tar.gz格式 - Maven:从Apache官网下载
apache-maven-3.9.x-bin.tar.gz
用U盘或跳板机传到服务器后,统一解压到/opt目录:
tar -zxvf jdk-17_linux-x64_bin.tar.gz -C /opt/
tar -zxvf apache-maven-3.9.6-bin.tar.gz -C /opt/
然后配置环境变量,编辑/etc/profile,在末尾加上具体路径:
export JAVA_HOME=/opt/jdk-17.0.10
export MAVEN_HOME=/opt/apache-maven-3.9.6
export PATH=$JAVA_HOME/bin:$MAVEN_HOME/bin:$PATH
执行source /etc/profile让配置生效,这一步建议逐个执行命令验证,不要一次复制多行,否则环境变量没加载成功时不易排查。
本地打包与产物传输的完整操作
部署的关键不是把源码拷到服务器上再编译,而是在本地打成一个可执行的Jar包,然后只传输产物,这个思路能显著降低服务器的资源占用,也能保证打包过程的重现性。
用Maven命令打出可直接运行的Jar包
进入项目根目录,执行:
mvn clean package -DskipTests
参数-DskipTests跳过单元测试,节省大量时间,如果你需要指定环境(比如dev、prod),加上-Pprod这样的profile参数即可,打包完成后,在target目录下能看到两类Jar包:
项目名-0.0.1-SNAPSHOT.jar:可执行文件,包含所有依赖项目名-0.0.1-SNAPSHOT.jar.original:仅包含项目自身代码,一般不用
用ls -lh target/.jar确认文件大小,一个完整的Spring Boot项目Jar通常在50MB到200MB之间,如果只有几KB,说明打包配置有问题,不要着急上传。
用scp命令将Jar包安全送到服务器
在本地终端执行:
scp target/myapp-0.0.1-SNAPSHOT.jar root@服务器IP:/opt/myapp/
首次连接会提示确认指纹,输入yes回车,然后输入服务器密码,文件较大时建议用rsync替代,支持断点续传:
rsync -avP target/myapp-0.0.1-SNAPSHOT.jar root@服务器IP:/opt/myapp/
在服务器上建议统一建一个/opt/myapp目录存放Jar包,不要随意丢在/root或/tmp下,后续做日志切割和备份时能省不少事。
三种常见启动方式对比与选择
Jar包上传完成后,接下来是启动环节,不同的启动方式对应不同的运维场景,选错了后面维护时会非常难受。
nohup直接启动(适合临时验证)
这是最快的启动方式,适合第一次验证代码能否跑通:
nohup java -jar myapp.jar --spring.profiles.active=prod > app.log 2>&1 &
启动后立即查看日志:tail -f app.log,如果看到Started Application in X seconds字样,说明启动成功,这种方式最大的问题是进程管理很弱进程意外崩溃后不会自动拉起,重启还要先ps -ef找PID再kill,繁琐得很。
systemd服务托管(适合长期运行)
这是目前生产环境的标准做法,创建一个服务配置文件:
vim /etc/systemd/system/myapp.service
写入如下配置,注意User和ExecStart的路径替换成实际值:
[Unit]
Description=My Spring Boot Application
After=network.target
[Service]
User=root
ExecStart=/usr/bin/java -jar /opt/myapp/myapp.jar --spring.profiles.active=prod
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
然后依次执行:
systemctl daemon-reload
systemctl enable myapp
systemctl start myapp
用systemctl status myapp查看运行状态。Restart=always能保证进程崩溃时自动拉起,配合RestartSec=5做五秒后重试,这是目前较为稳妥和用的多的防护机制。
Docker容器化部署(适合云原生场景)
如果你的服务器已经装了Docker,可以用更隔离的方式运行:
docker run -d --name myapp \
-p 8080:8080 \
-e SPRING_PROFILES_ACTIVE=prod \
-v /opt/myapp/logs:/logs \
myapp-image:latest
用Docker的优势在于环境完全隔离,不会污染宿主机,回滚也方便,但要额外维护镜像构建流程,对于单机部署的小项目来说,收益并不太明显。
Nginx反向代理与端口映射配置
Spring Boot应用默认监听8080端口,直接对外暴露不仅不安全,而且无法做负载均衡,生产中普遍用Nginx做反向代理,把80端口的请求转发给8080,同时还可以顺便托管静态资源。
配置Nginx配置文件的server块
在/etc/nginx/conf.d/目录下新建myapp.conf,写入:
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /static/ {
alias /opt/myapp/static/;
expires 7d;
}
}
其中proxy_set_header这几行很重要,它们能保证后端应用能拿到用户的真实IP,在运维实践中,相当一部分应用日志里看不到真实IP,都是因为少了这些配置。
改完配置后执行:
nginx -t
systemctl reload nginx
看到test is successful即可,然后你就可以用http://服务器IP访问应用了,8080端口完全不必对外开放。
防火墙与安全组放行规则
这是新手最容易卡住的地方应用明明启动了,Nginx也配置好了,但外部就是访问不了,通常是两个位置需要放行:
- 云服务器安全组(在控制台操作):添加入站规则,放行TCP 80端口
- 操作系统防火墙:CentOS执行
firewall-cmd --add-port=80/tcp --permanent,Ubuntu执行ufw allow 80
如果要放开8080端口做调试,调完后记得及时关闭,尽量少暴露不必要的端口。
高频故障排查清单
部署完成后如果访问异常,按下面顺序排查,多数问题能在三分钟内定位,在面试或日常交流中,这一套思路也常被拿来考察候选人的部署经验。
- 查看应用状态:
systemctl status myapp,确认处于active (running)状态 - 查看应用日志:
journalctl -u myapp -n 100,关注最后的异常堆栈 - 确认端口监听:
ss -tlnp | grep 8080,看java进程是否真正监听 - 测试本地回环:
curl http://127.0.0.1:8080,能通说明应用层面没问题 - 测试外部访问:
curl http://服务器IP,如果这里失败,继续查安全组
Maven项目部署云服务器时遇到内存不足怎么办
很多云服务器配置不高,尤其1核2G的入门型实例跑Spring Boot 3项目容易触发OutOfMemoryError,可以在启动命令中限制堆内存:
java -Xms256m -Xmx512m -jar myapp.jar
同时确保服务器上没有其他占用内存的大进程,建议用free -h查看内存余量,如果物理内存本身就比较紧张,调大Swap文件是优先级较高的解决办法。
服务器端口占用导致应用启动失败如何识别与解决
Port 8080 was already in use是另一类高频报错,先找占用进程:
lsof -i:8080
或者
ss -tlnp | grep 8080
如果确认是之前的残留进程,用kill -9 进程PID结束它,然后重启服务,如果你的应用必须使用8080端口,而其他程序又占用着这个端口,可以考虑改application.yml里的server.port,或者配置Nginx转发到其他端口。
两个常见的部署场景差异
maven项目发布到内网服务器与部署到云服务器在操作上有明显区别,内网服务器通常没有外网访问权限,需要离线安装JDK和Maven,并通过内网Nexus仓库拉取依赖,在settings.xml里配置好内网仓库地址:
<mirror>
<id>nexus</id>
<name>local nexus</name>
<url>http://192.168.1.100:8081/repository/maven-public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
云服务器则天生具备外网访问能力,包管理器直接安装依赖即可,但云服务器需要额外关注安全组规则和公网带宽,这些参数在套餐里默认可能比较保守,需要按需调整。
部署完成后的发布上线检查清单
项目能跑起来只是第一步,对外提供服务前还建议做一次全面自查,这组检查项也可以沉淀为团队的标准操作流程,方便新同事参考执行。
- 接口健康检查:确认
/actuator/health返回{"status":"UP"},确保注册中心、配置中心都连上了 - 定时任务确认:如果一个服务部署了多个实例,检查定时任务是否配置了分布式锁,避免同一条数据被重复处理
- 日志轮转配置:在
logback-spring.xml里配置按天滚动和大小限制,避免应用长期运行把磁盘占满 - 数据库连接池校验:确认
hikari的最大连接数设置合理,和数据库max_connections匹配,防止连接数打满报错 - 备份当前Jar包:执行
cp myapp.jar myapp.jar.bak_$(date +%Y%m%d),为回滚留好退路
部署Maven项目到新服务器本身并不复杂,核心思路就是打包、传输、运行、代理、校验这五个环节,按文中的流程走一遍,多数场景下的部署问题都能平稳解决,后续如果涉及多台服务器的批量发布,再考虑引入Jenkins或GitLab CI做流水线,那将是另一个更加自动化的话题。
常见部署问题解答
服务器内存多大才能运行Maven项目?
如果只是部署一个常规的Spring Boot应用,2GB内存是目前比较稳妥的起步配置,项目Jar包本身只占磁盘空间,运行时JVM默认堆内存是物理内存的四分之一,2G内存下默认最大堆为512MB,对大多数中小型业务足够使用,如果预算允许,4G内存会更宽松,能容纳更复杂的业务逻辑和更充裕的JVM调优空间,1G内存的机器也能跑,但需要显式限制-Xmx512m,整体容错能力比较有限。
打包时提示BUILD FAILURE如何排查?
最常见的原因是依赖下载失败或测试用例报错,先尝试加-DskipTests跳过测试,如果仍然失败,查看错误日志中ERROR开头的行,定位到具体依赖坐标,在多数情况下,将本机~/.m2/repository目录下对应的依赖文件夹整个删掉,重新执行mvn clean package,问题就能解决这是本地仓库缓存损坏后的标准修复手段。
scp上传Jar包时速度很慢怎么办?
如果业务对时效性的要求比较严格,建议先压缩再传输:
tar -czf myapp.tar.gz myapp.jar
scp myapp.tar.gz root@服务器IP:/opt/myapp/
到服务器上再解压tar -xzf myapp.tar.gz,当服务器带宽比较有限时,压缩传输通常比直接传原包快出一截,如果服务器和本地都在内网,换用rsync配合--compress选项,传输效率也会更好。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/784363.html


