【Tomcat 核心实战手册:涵盖安装部署、Jenkins/jspgou 应用部署、多实例与动静分离,搭配 JVM 堆 / 元空间配置、GC 开启及排障工具使用】

Tomcat与JVM核心实战指南

提示:本文原创作品,良心制作,干货为主,简洁清晰,一看就会


一、Tomcat简介

1.1 什么是tomcat

Tomcat 是Apache软件基金会(Apache Software Foundation)的一个开源 Java Web 中间件,本质上是一个 Servlet 容器,它基于 Java 技术构建,核心作用是

  • 作为 Servlet 容器和 JSP 解析器,承载 Java Web 应用的运行
  • 接收客户端 HTTP 请求,将动态资源请求(如Servlet、JSP)转发给对应组件处理
  • 管理 Servlet 生命周期,解析 JSP 为 Servlet 执行,处理业务逻辑

1.2 为什么要学tomcat

因为市面上Java 在后端开发中占比极高,电商、金融、政企系统等大多用 Java 构建,这些项目都需要中间件承载运行,而tomcat是开源且成熟的 Java Web 中间件,轻量、稳定又易部署,能直接解析运行 Servlet、JSP 等 Java Web 核心组件,是 Java 项目部署的 “标配工具”


二、Tomcat与JDK

Tomcat作为Java Web中间件,完全依赖JDK环境。 没有JDK,Tomcat无法启动;JDK版本需与Tomcat兼容(如高版本Tomcat需匹配高版本JDK),否则会出现运行异常
其中JDK包括:
JVM:Java虚拟机,翻译java程序给cpu识别
JRE:Java运行时环境
Java类库:import,jdbc等各种功能模块


三、Tomcat安装

3.1 安装jdk

安装tomcat前先要准备好jdk环境
JDK官网:https://www.oracle.com/cn/java/technologies/downloads/

#安装jdk
root@tomcat:~# ls
jdk-8u211-linux-x64.tar.gz   //我这里下载的时jdk1.8
root@tomcat:~# tar xf jdk-8u211-linux-x64.tar.gz -C /usr/local
root@tomcat:~# ls /usr/local/
bin  etc  games  include  jdk1.8.0_211  lib  man  mysql  mysql-8.0.37  sbin  share  src
root@tomcat:~# mv /usr/local/jdk1.8.0_211/  /usr/local/java
root@tomcat:~# vim /etc/profile  //在最后添加上这两行
export JAVA_HOME=/usr/local/java
export PATH=$PATH:$JAVA_HOME/bin
root@tomcat:~# 
root@tomcat:~# source /etc/profile
root@tomcat:~# java -version   //查看版本
java version "1.8.0_211"
Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)

3.2 安装tomcat

Tomcat官网:https://tomcat.apache.org/

//安装tomcat
root@tomcat:~# ls  //我下载的版本是8.5.45
apache-tomcat-8.5.45.tar.gz  jdk-8u211-linux-x64.tar.gz  
root@tomcat:~# mkdir -p /data/application
root@tomcat:~# tar xf apache-tomcat-8.5.45.tar.gz -C /data/application/
root@tomcat:~# ls /data/application/
apache-tomcat-8.5.45
root@tomcat:~# mv /data/application/apache-tomcat-8.5.45/ /data/application/tomcat
root@tomcat:~# 
root@tomcat:~# /data/application/tomcat/bin/startup.sh  //启动tomcat
//tomcat启动后会占用3个端口
//8080 http用的
//8005 负责监听关闭tomcat的请求
//8009 与其他服务通信的端口
root@tomcat:~# netstat -tanlp | grep 80
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1714/nginx: master  
tcp6       0      0 :::8080                 :::*                    LISTEN      5943/java           
tcp6       0      0 :::80                   :::*                    LISTEN      1714/nginx: master  
tcp6       0      0 127.0.0.1:8005          :::*                    LISTEN      5943/java           
tcp6       0      0 :::8009                 :::*                    LISTEN      5943/java           

访问ip:8080
在这里插入图片描述


3.3 tomcat目录介绍

root@tomcat:~# cd /data/application/tomcat/
root@tomcat:/data/application/tomcat# tree -L 1  #相当于ls
.
├── bin  //存放tomcat管理脚本,其中startup.sh启动,shutdown.sh停止,version.sh查看tomcat版本,
├── BUILDING.txt
├── conf  //配置文件存放目录,其中server.xml尤为重要,里面可以改端口等各种信息
├── CONTRIBUTING.md
├── lib  //web应用调用的jar包存放路径
├── LICENSE
├── logs  //存放日志,catalina.out是核心日志文件,localhost_access_log记录访问日志
├── NOTICE
├── README.md
├── RELEASE-NOTES
├── RUNNING.txt
├── temp
├── webapps  //默认网站发布目录,其中/ROOT/index.jsp是默认网页
└── work

四、Tomcat实例

4.1 tomcat上安装Jenkins

server.xml配置文件中有两个参数:unpackWARsautoDeploy
unpackWARs:如果为true,则tomcat会自动将WAR文件解压,否则不解压,直接从WAR文件中运行应用程序
autoDeploy:在tomcat启动时,是否自动部署
appBase指定发布目录,此目录可以修改

root@tomcat:~# vim /data/application/tomcat/conf/server.xml 
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

所以直接把Jenkins的war包放在发布目录下,tomcat会自动解压部署
jenkins官网:https://www.jenkins.io/download/

root@tomcat:~# /data/application/tomcat/bin/startup.sh
root@tomcat:~# rm -rf /data/application/tomcat/webapps/*
root@tomcat:~# ls
apache-tomcat-8.5.45.tar.gz  jdk-8u211-linux-x64.tar.gz jenkins.war
root@tomcat:~# mv jenkins.war /data/application/tomcat/webapps/
root@tomcat:~# /data/application/tomcat/bin/startup.sh 
root@tomcat:~# ls /data/application/tomcat/webapps/
jenkins  jenkins.war

访问网页,然后查看密码cat /root/.jenkins/secrets/initialAdminPassword
在这里插入图片描述
到这一步Jenkins已经安装成功
在这里插入图片描述


4.2 一台机器上运行多实例tomcat

这里演示一台机器上运行两个tomcat
只需要让它们端口不一致即可

root@tomcat:~# rm -rf /data/application/*
root@tomcat:~# ls
apache-tomcat-8.5.45.tar.gz  jdk-8u211-linux-x64.tar.gz  
root@tomcat:~# tar xf apache-tomcat-8.5.45.tar.gz -C /data/application/
root@tomcat:~# ls /data/application/
apache-tomcat-8.5.45
root@tomcat:~# mv /data/application/apache-tomcat-8.5.45/ /data/application/tomcat1
root@tomcat:~# tar xf apache-tomcat-8.5.45.tar.gz -C /data/application/
root@tomcat:~# mv /data/application/apache-tomcat-8.5.45/ /data/application/tomcat2
root@tomcat:~# ls /data/application/
tomcat1  tomcat2
#修改端口8005-->8006  8009-->8010  8080-->8081
root@tomcat:~# vim /data/application/tomcat2/conf/server.xml  
...
<Server port="8006" shutdown="SHUTDOWN">
...
<Connector port="8010" protocol="AJP/1.3" redirectPort="8443" />
...
<Connector port="8081" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
...
root@tomcat:~# /data/application/tomcat1/bin/startup.sh  #启动tomcat1
root@tomcat:~# /data/application/tomcat2/bin/startup.sh  #启动tomcat2
root@tomcat:~# netstat -tanlp | grep 80
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1782/nginx: master  
tcp6       0      0 127.0.0.1:8006          :::*                    LISTEN      3727/java           
tcp6       0      0 :::8009                 :::*                    LISTEN      3669/java           
tcp6       0      0 :::8010                 :::*                    LISTEN      3727/java           
tcp6       0      0 :::8080                 :::*                    LISTEN      3669/java           
tcp6       0      0 :::80                   :::*                    LISTEN      1782/nginx: master  
tcp6       0      0 :::8081                 :::*                    LISTEN      3727/java           
tcp6       0      0 127.0.0.1:8005          :::*                    LISTEN      3669/java           
tcp6       0      0 ::1:42140               ::1:8080                TIME_WAIT   -                   
tcp6       0      0 127.0.0.1:47354         127.0.0.1:8005          TIME_WAIT   -                   
tcp6       0      0 ::1:8009                ::1:38770               TIME_WAIT   -                   
root@tomcat:~# 

访问相同ip的不同端口
在这里插入图片描述
在这里插入图片描述


4.3 tomcat上部署jspgou商城

先去网上下载jspgou商场的zip包
本实验还需要用到mysql

root@tomcat:~# ls
apache-tomcat-8.5.45.tar.gz  DB  jdk-8u211-linux-x64.tar.gz  jspgouV6-ROOT.zip  
root@tomcat:~# unzip jspgouV6.1-ROOT.zip  #解压
root@tomcat:~# ls  #DB下是sql的逻辑备份语句,需要导入数据库
apache-tomcat-8.5.45.tar.gz  DB  jdk-8u211-linux-x64.tar.gz  jspgouV6-ROOT.zip   ROOT  
root@tomcat:~# 
root@tomcat:~# ls /data/application/tomcat/webapps/
docs  examples  host-manager  manager  ROOT
root@tomcat:~# rm -rf /data/application/tomcat/webapps/*
root@tomcat:~# cp -r ROOT/ /data/application/tomcat/webapps/  #将ROOT目录拷贝到tomcat的发布目录下
root@tomcat:~# ls /data/application/tomcat/webapps/
ROOT
root@tomcat:~# mysql -p'Qing@123'
mysql> create database jspgou default charset=utf8;   #创建库,待会需要导入数据

mysql> set global sql_mode='NO_ENGINE_SUBSTITUTION';  #临时关闭严格模式

mysql> set session sql_mode='NO_ENGINE_SUBSTITUTION';

mysql> \q

root@tomcat:~# vim /data/application/tomcat/webapps/ROOT/WEB-INF/config/jdbc.properties 
...
#我的mysql是在本机,所以ip不用改,你们的mysql在哪台机器上就写哪台的ip
#刚才创建的什么库这里就写什么库,我创建的是jspgou
jdbc.url=jdbc:mysql://127.0.0.1:3306/jspgou?characterEncoding=UTF-8   
jdbc.username=root  #mysql登录账户
jdbc.password=Qing@123  #登录密码
...
root@tomcat:~# mysql -uroot -p'Qing@123' jspgou < DB/jspgou.sql   #导入数据
root@tomcat:~# /data/application/tomcat/bin/startup.sh   #启动tomcat
root@tomcat:~# netstat -tanlp | grep 80
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1782/nginx: master  
tcp        0      0 127.0.0.1:3306          127.0.0.1:47180         ESTABLISHED 1755/mysqld         
tcp6       0      0 :::8009                 :::*                    LISTEN      5055/java           
tcp6       0      0 :::8080                 :::*                    LISTEN      5055/java           
tcp6       0      0 :::80                   :::*                    LISTEN      1782/nginx: master  
tcp6       0      0 127.0.0.1:8005          :::*                    LISTEN      5055/java           
tcp6       0      0 127.0.0.1:47180         127.0.0.1:3306          ESTABLISHED 5055/java           
root@tomcat:~# 

访问网页,jspgou商场搭建完毕
在这里插入图片描述


4.4 tomcat配合nginx实现动静分离

4.1.1 环境介绍

大部分情况下,nginx提供静态页面,tomcat提供动态页面
对nginx不了解的可以看这个专栏https://blog.csdn.net/m0_63756214/category_13055829.html
实验环境:

主机名IP地址占用端口服务作用
tomcat192.168.136.1348080tomcat提供动态页面
tomcat192.168.136.13480nginx提供静态页面
nginx192.168.136.13580nginx负载均衡器

4.1.2 页面制作

#动态页面准备
root@tomcat:~# rm -rf /data/application/*
root@tomcat:~# tar xf apache-tomcat-8.5.45.tar.gz -C /data/application/
root@tomcat:~# mv /data/application/apache-tomcat-8.5.45/ /data/application/tomcat
root@tomcat:~# vim /data/application/tomcat/webapps/ROOT/index.jsp #我这写了一个生成随机数的页面
root@tomcat:~# /data/application/tomcat/bin/startup.sh 

访问网页
请添加图片描述

#静态页面准备
root@tomcat:~# vim /var/www/html/index.nginx-debian.html #去nginx的页面随便写点什么都行
root@tomcat:~# systemctl start nginx

访问网页
在这里插入图片描述

4.1.2 配置负载均衡

#nginx做负载均衡器实现动静分离
root@nginx:~# vim /etc/nginx/conf.d/test.conf 
upstream static {
    server 192.168.136.134:80;
}
upstream dynamic {
    server 192.168.136.134:8080;
}
server {
    listen 80;
    server_name localhost;

    # 静态页面:匹配所有 .html 结尾的请求
    location ~ \.html$ {
        proxy_pass http://static;
        proxy_set_header Host $host;  # 去掉 $server_port,避免后端端口错误
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    # 动态页面:匹配所有 .jsp 结尾的请求
    location ~ \.jsp$ {
        proxy_pass http://dynamic;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
root@nginx:~# 

访问网页
请添加图片描述


五、扩展

5.1常用JVM虚拟机参数

JVM 虚拟机提供了三种类型参数:标准参数X类型参数XX类型参数
这里我们着重讲一下XX类型参数
用一句话来说明 XX 参数的语法。所有的 XX 参数都以"-XX:"开始,但是随后的语法不同,取决于参数的类型:

  • 对于布尔类型的参数,我们有"+“或”-",然后才设置 JVM 选项的实际名称
    例:-XX:+ 用于激活选项,而 -XX:- 用于注销选项。
    例:开启GC日志的参数: -XX:+PrintGC
  • 对于非布尔值的参数,如 string 或者 integer,我们先写参数的名称,后面加上"=",最后赋值
    例:-XX:MaxPermSize=2048m

5.2 开启JAVA虚拟机的垃圾回收

要跟踪 Java 虚拟机(JVM)的垃圾回收(GC)过程,可通过添加 JVM 启动参数 开启 GC 日志,记录 GC 的触发时间、类型、回收内存大小、耗时等详细信息
开启 GC 日志不会直接提升应用性能,但是可直观了解 JVM 的垃圾回收行为,帮助排查内存泄漏、优化 GC 性能(如调整堆内存大小、选择合适的 GC 收集器)

5.2.1 JDK 8 及以下版本常用参数

参数作用说明
-XX:+PrintGCDetails打印 GC 详细信息(包括回收前后各内存区域大小、耗时等)
-XX:+PrintGCDateStamps输出 GC 发生的时间戳(格式:YYYY-MM-DDTHH:MM:SS),便于定位时间点
-Xloggc:/path/to/gc.log指定 GC 日志输出文件路径(需确保目录有写入权限)
-XX:+PrintGC简化版 GC 日志(仅显示 GC 类型、耗时、堆内存变化,信息较少)
-XX:+PrintGCTimeStamps输出 GC 发生的相对时间戳(从 JVM 启动开始计算的秒数)

5.2.1 GC配置方法

#开启GC日志
vim /tomcat/bin/catalina.sh  # 在文件开头(#!/bin/sh 下方)添加
export JAVA_OPTS="-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/usr/local/tomcat/logs/gc.log"

5.2.3 GC注意事项

日志滚动
JDK 8 需配合 -XX:+UseGCLogFileRotation 等参数实现日志滚动(避免单文件过大):

# JDK 8 日志滚动配置(最多 5 个文件,每个 100MB)
-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=100M

权限问题
确保日志输出目录(如 /path/to/)有写入权限,否则 JVM 启动会失败


5.3 配置JAVA虚拟机的堆空间

堆内存是 JVM 中最大的内存区域,专门用于存储对象实例,是垃圾回收GC的主要区域
控制 JVM 堆内存的两个关键参数:
-Xms:设置堆内存的初始大小(JVM 启动时分配的内存)
-Xmx:设置堆内存的最大大小(JVM 运行中允许使用的最大内存)
通常建议将 Xms 和 Xmx 设置为相同值,避免 JVM 频繁调整堆内存大小,减少性能损耗

# 设置堆内存初始值和最大值(单位:m 表示兆字节,g 表示千兆字节)
vim /tomcat/bin/catalina.sh  # 在文件开头(#!/bin/sh 下方)添加
export JAVA_OPTS="-Xms512m -Xmx1024m"

5.4 配置JAVA虚拟机的元数据区域

元空间用于存储类元数据(如类结构、方法信息、注解等)。元空间默认使用操作系统的本地内存(而非 JVM 堆内存),但可以通过 JVM 参数进行配置,避免其无限制占用系统资源

5.4.1 元空间参数

元空间的核心配置参数有两个,分别控制其初始阈值和最大内存限制:

参数作用说明
-XX:MetaspaceSize设置元空间的初始触发 GC 阈值(默认约 21MB,不同 JDK 版本略有差异)
当元空间使用量达到该值时,会触发元空间的垃圾回收(GC),并动态调整后续阈值
-XX:MaxMetaspaceSize设置元空间的最大内存上限(默认无限制,仅受系统可用内存限制)
若不设置,元空间可能因类加载过多(如动态生成类)导致本地内存溢出(OOM)

5.4.2 元空间配置方法

启动 Jar 包时配置直接在启动命令中添加参数

# 元空间初始阈值 128MB,最大限制 256MB
java -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -jar your-application.jar

Tomcat 中配置
编辑 Tomcat 的 bin/catalina.sh 文件,在开头添加参数:

vim /tomcat/bin/catalina.sh  # 在文件开头(#!/bin/sh 下方)添加
export JAVA_OPTS="-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m"

容器化部署(Docker)
在 Dockerfile 或启动命令中通过 JAVA_OPTS 传递参数:

# Dockerfile 示例
FROM openjdk:11-jre-slim
ENV JAVA_OPTS="-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m"
CMD ["sh", "-c", "java $JAVA_OPTS -jar /app/your-application.jar"]

5.4.3 验证配置是否生效

查看 JVM 进程参数

# 查找 Java 进程 ID
ps -ef | grep java

# 查看元空间配置(替换 PID 为实际进程号)
jinfo -flags PID | grep Metaspace

若输出包含 MetaspaceSize=134217728(128m)和 MaxMetaspaceSize=268435456(256m),则配置生效

查看 GC 日志
元空间相关的 GC 日志会显示元空间的使用量、GC 前后的大小变化,例如:

[GC (Metadata GC Threshold) ... Metaspace: 128.0M->128.0M(256.0M)]

5.5 JVM运维排障工具

5.5.1 jps

jps是列出当前系统中所有正在运行的 Java 进程,类似 ps 命令但专门针对 Java 进程

root@tomcat:~# jps
5680 Bootstrap  # tomcat进程
9262 Jps  # jps自身进程
root@tomcat:~# 

5.5.2 jstack

jstack生成指定 Java 进程的线程堆栈跟踪信息,包括线程状态、调用栈、锁信息等,主要用于排查线程死锁、线程阻塞、CPU 占用过高等问题

jstack [选项] <进程 PID>


注:
文中若有疏漏,欢迎大家指正赐教。
本文为100%原创,转载请务必标注原创作者,尊重劳动成果。
求赞、求关注、求评论!你的支持是我更新的最大动力,评论区等你~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值