📋 学习目标
- 掌握部署方式 - JAR包与WAR包部署
- 了解Tomcat配置 - 内嵌与外部Tomcat
- 学会性能优化 - 连接池与JVM调优
- 掌握监控技巧 - 应用状态监控
- 了解安全配置 - HTTPS与安全策略
- 学会故障排查 - 日志分析与调试
📦 部署方式
- JAR包部署 - 内嵌Tomcat,独立运行
- WAR包部署 - 外部Tomcat容器
- Docker部署 - 容器化部署
- 云平台部署 - 云服务器部署
- 集群部署 - 负载均衡部署
- 蓝绿部署 - 零停机部署
📦 JAR包部署配置
<!-- pom.xml JAR包配置 -->
<project>
<groupId>cn.bugstack.springframework.boot</groupId>
<artifactId>chapter-12-tomcat</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<!-- SpringBoot Web启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringBoot Actuator监控 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!-- SpringBoot Maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
</plugins>
</build>
</project>
# application.yml JAR包配置
server:
port: 8080
servlet:
context-path: /api
tomcat:
# 连接器配置
max-connections: 8192
accept-count: 100
max-threads: 200
min-spare-threads: 10
# 连接超时
connection-timeout: 20000
# 压缩配置
compression:
enabled: true
mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json
min-response-size: 1024
# 启动脚本 start.sh
#!/bin/bash
APP_NAME="chapter-12-tomcat"
JAR_NAME="$APP_NAME-1.0-SNAPSHOT.jar"
PID_FILE="$APP_NAME.pid"
# JVM参数配置
JVM_OPTS="-Xms512m -Xmx1024m"
JVM_OPTS="$JVM_OPTS -XX:+UseG1GC"
JVM_OPTS="$JVM_OPTS -XX:MaxGCPauseMillis=200"
JVM_OPTS="$JVM_OPTS -XX:+PrintGCDetails"
JVM_OPTS="$JVM_OPTS -Xloggc:gc.log"
# 启动应用
nohup java $JVM_OPTS -jar $JAR_NAME > app.log 2>&1 &
echo $! > $PID_FILE
echo "应用启动成功,PID: $(cat $PID_FILE)"
🔄 部署流程
1
代码构建
使用Maven或Gradle构建JAR/WAR包
2
环境准备
配置服务器环境,安装JDK和Tomcat
📁 WAR包部署配置
<!-- pom.xml WAR包配置 -->
<project>
<packaging>war</packaging>
<dependencies>
<!-- SpringBoot Web启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 排除内嵌Tomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
// SpringBootServletInitializer.java
@SpringBootApplication
public class TomcatApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(TomcatApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(TomcatApplication.class, args);
}
}
<!-- Tomcat server.xml 配置 -->
<Server port="8005" shutdown="SHUTDOWN">
<Service name="Catalina">
<!-- HTTP连接器 -->
<Connector port="8080"
protocol="HTTP/1.1"
connectionTimeout="20000"
maxThreads="200"
minSpareThreads="10"
maxConnections="8192"
acceptCount="100"
compression="on"
compressionMinSize="1024"
compressableMimeType="text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json"
redirectPort="8443" />
<!-- HTTPS连接器 -->
<Connector port="8443"
protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150"
SSLEnabled="true"
scheme="https"
secure="true"
clientAuth="false"
sslProtocol="TLS"
keystoreFile="conf/keystore.jks"
keystorePass="password" />
<Engine name="Catalina" defaultHost="localhost">
<Host name="localhost"
appBase="webapps"
unpackWARs="true"
autoDeploy="true">
<!-- 应用上下文配置 -->
<Context path="/api"
docBase="chapter-12-tomcat.war"
reloadable="false">
<!-- 数据源配置 -->
<Resource name="jdbc/dataSource"
auth="Container"
type="javax.sql.DataSource"
maxTotal="20"
maxIdle="10"
maxWaitMillis="10000"
username="root"
password="password"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/springboot" />
</Context>
</Host>
</Engine>
</Service>
</Server>
# Tomcat启动脚本 catalina.sh
export JAVA_OPTS="-Xms1024m -Xmx2048m"
export JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC"
export JAVA_OPTS="$JAVA_OPTS -XX:MaxGCPauseMillis=200"
export JAVA_OPTS="$JAVA_OPTS -Dspring.profiles.active=prod"
export JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF-8"
export JAVA_OPTS="$JAVA_OPTS -Djava.security.egd=file:/dev/./urandom"
⚡ Tomcat优化
- 连接器优化 - 线程池与连接数
- 内存优化 - JVM堆内存配置
- GC优化 - 垃圾回收器选择
- 压缩配置 - HTTP响应压缩
- 缓存策略 - 静态资源缓存
- 安全配置 - 安全头与过滤器
📊 监控运维
- 健康检查 - Actuator端点监控
- 性能监控 - JVM与应用指标
- 日志管理 - 日志收集与分析
- 告警配置 - 异常状态告警
- 备份策略 - 数据与配置备份
- 故障恢复 - 快速故障恢复
⚡ 性能优化配置
# application-prod.yml 生产环境配置
server:
tomcat:
# 线程配置
max-threads: 200
min-spare-threads: 20
max-connections: 8192
accept-count: 100
# 连接超时配置
connection-timeout: 20000
keep-alive-timeout: 60000
max-keep-alive-requests: 100
# 压缩配置
compression:
enabled: true
mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json,application/xml
min-response-size: 1024
# 访问日志配置
accesslog:
enabled: true
directory: logs
file-date-format: .yyyy-MM-dd
pattern: '%t %a "%r" %s (%D ms)'
# HTTP/2支持
http2:
enabled: true
# JVM优化参数
# -Xms2g -Xmx4g
# -XX:+UseG1GC
# -XX:MaxGCPauseMillis=200
# -XX:+UseStringDeduplication
# -XX:+PrintGCDetails
# -XX:+PrintGCTimeStamps
# -Xloggc:gc.log
# 连接池配置
spring:
datasource:
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
leak-detection-threshold: 60000
# 缓存配置
cache:
type: caffeine
caffeine:
spec: maximumSize=1000,expireAfterWrite=5m
# 监控配置
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
metrics:
export:
prometheus:
enabled: true
// TomcatCustomizer.java - Tomcat自定义配置
@Component
public class TomcatCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory factory) {
// 自定义连接器
factory.addConnectorCustomizers(connector -> {
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
// 设置最大线程数
protocol.setMaxThreads(200);
protocol.setMinSpareThreads(20);
// 设置连接超时
protocol.setConnectionTimeout(20000);
protocol.setKeepAliveTimeout(60000);
// 启用压缩
protocol.setCompression("on");
protocol.setCompressionMinSize(1024);
// 设置最大连接数
protocol.setMaxConnections(8192);
protocol.setAcceptCount(100);
});
// 添加错误页面
factory.addErrorPages(
new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"),
new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500")
);
// 设置会话超时
factory.addInitializers(servletContext -> {
servletContext.getSessionCookieConfig().setMaxAge(30 * 60); // 30分钟
});
}
}
// PerformanceFilter.java - 性能监控过滤器
@Component
@Order(1)
public class PerformanceFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(PerformanceFilter.class);
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
long startTime = System.currentTimeMillis();
try {
chain.doFilter(request, response);
} finally {
long duration = System.currentTimeMillis() - startTime;
// 记录慢请求
if (duration > 1000) {
logger.warn("慢请求: {} {} 耗时: {}ms",
httpRequest.getMethod(),
httpRequest.getRequestURI(),
duration);
}
// 记录性能指标
Metrics.timer("http.request.duration",
"method", httpRequest.getMethod(),
"uri", httpRequest.getRequestURI())
.record(duration, TimeUnit.MILLISECONDS);
}
}
}
📊 部署方式对比
部署方式 |
优点 |
缺点 |
适用场景 |
JAR包部署 |
简单快速、内嵌容器、独立运行 |
资源占用较高、升级需重启 |
微服务、云原生应用 |
WAR包部署 |
资源共享、统一管理、热部署 |
配置复杂、容器依赖 |
传统企业应用 |
Docker部署 |
环境一致、易扩展、版本管理 |
学习成本、资源开销 |
容器化环境 |
云平台部署 |
弹性伸缩、高可用、托管服务 |
成本较高、厂商绑定 |
大规模应用 |
🔧 故障排查
🚨 常见问题与解决方案
启动失败 - 检查端口占用、配置文件、依赖冲突
内存溢出 - 调整JVM参数、优化代码、增加内存
响应缓慢 - 分析线程池、数据库连接、网络延迟
连接超时 - 检查网络配置、防火墙、负载均衡
日志异常 - 查看错误日志、堆栈信息、系统资源
# 故障排查命令
# 1. 检查应用进程
ps aux | grep java
# 2. 检查端口占用
netstat -tlnp | grep 8080
lsof -i :8080
# 3. 查看JVM信息
jps -l
jinfo <pid>
jstat -gc <pid> 1s
# 4. 生成堆转储
jmap -dump:format=b,file=heapdump.hprof <pid>
# 5. 查看线程信息
jstack <pid>
# 6. 监控系统资源
top -p <pid>
iostat 1
free -h
# 7. 查看应用日志
tail -f application.log
grep ERROR application.log
grep -A 10 -B 10 "OutOfMemoryError" application.log
# 8. 网络诊断
ping <host>
telnet <host> <port>
curl -I http://localhost:8080/actuator/health