第四章-Tomcat线程模型与运行方式

🧵 第四章:Tomcat 线程模型与运行方式

目录

  • [4.1 线程模型概述](#4.1 线程模型概述)
  • [4.2 支持的 I/O 模式](#4.2 支持的 I/O 模式)
  • [4.3 线程生命周期管理](#4.3 线程生命周期管理)
  • [4.4 运行模式详解](#4.4 运行模式详解)
  • [4.5 性能对比分析](#4.5 性能对比分析)
  • [4.6 配置优化建议](#4.6 配置优化建议)
  • [4.7 本章小结](#4.7 本章小结)

4.1 线程模型概述

4.1.1 线程模型架构

整体架构图

业务处理 Worker 线程池 Poller 线程 Acceptor 线程 Servlet 处理 业务逻辑 数据库操作 Worker 1 Worker 2 Worker 3 Worker N Poller 1 Poller 2 Poller N Acceptor

线程职责分工
线程类型 职责 数量 生命周期
Acceptor 接受新连接 1个 长期运行
Poller 处理 I/O 事件 1-2个 长期运行
Worker 处理业务逻辑 可配置 按需创建

4.1.2 线程池配置

标准线程池
java 复制代码
// 标准线程池实现
public class StandardThreadExecutor implements Executor {
    private final ThreadPoolExecutor executor;
    private final String name;
    private final int maxThreads;
    private final int minSpareThreads;
    private final int maxSpareThreads;
    private final long keepAliveTime;
    
    public StandardThreadExecutor() {
        this.maxThreads = 200;
        this.minSpareThreads = 10;
        this.maxSpareThreads = 50;
        this.keepAliveTime = 60L;
        
        // 创建线程池
        this.executor = new ThreadPoolExecutor(
            minSpareThreads,           // 核心线程数
            maxThreads,                // 最大线程数
            keepAliveTime,             // 空闲时间
            TimeUnit.SECONDS,          // 时间单位
            new LinkedBlockingQueue<>(), // 工作队列
            new ThreadFactory() {      // 线程工厂
                private final AtomicInteger threadNumber = new AtomicInteger(1);
                private final String namePrefix = "http-nio-8080-exec-";
                
                @Override
                public Thread newThread(Runnable r) {
                    Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement());
                    t.setDaemon(false);
                    t.setPriority(Thread.NORM_PRIORITY);
                    return t;
                }
            }
        );
    }
    
    @Override
    public void execute(Runnable command) {
        executor.execute(command);
    }
}
自定义线程池
java 复制代码
// 自定义线程池配置
public class CustomThreadExecutor implements Executor {
    private final ThreadPoolExecutor executor;
    
    public CustomThreadExecutor() {
        // 核心线程数
        int corePoolSize = 10;
        // 最大线程数
        int maximumPoolSize = 200;
        // 空闲时间
        long keepAliveTime = 60L;
        // 时间单位
        TimeUnit unit = TimeUnit.SECONDS;
        // 工作队列
        BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(100);
        // 线程工厂
        ThreadFactory threadFactory = new ThreadFactory() {
            private final AtomicInteger threadNumber = new AtomicInteger(1);
            private final String namePrefix = "custom-exec-";
            
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement());
                t.setDaemon(false);
                t.setPriority(Thread.NORM_PRIORITY);
                return t;
            }
        };
        // 拒绝策略
        RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
        
        executor = new ThreadPoolExecutor(
            corePoolSize, maximumPoolSize, keepAliveTime, unit, 
            workQueue, threadFactory, handler);
    }
}

4.2 支持的 I/O 模式

4.2.1 BIO(阻塞 I/O)

特点
  • 阻塞模式:每个连接占用一个线程
  • 简单实现:代码逻辑简单,易于理解
  • 资源消耗:线程数量与连接数成正比
  • 适用场景:连接数较少,并发量不高的应用
实现原理
java 复制代码
// BIO 连接器实现
public class Http11Protocol extends AbstractHttp11Protocol<Socket> {
    @Override
    protected AbstractEndpoint.Handler<Socket> getHandler() {
        return new Http11ConnectionHandler(this);
    }
}

// BIO 连接处理器
public class Http11ConnectionHandler extends AbstractConnectionHandler<Socket, Http11Processor> {
    @Override
    protected Http11Processor createProcessor() {
        Http11Processor processor = new Http11Processor(this);
        processor.setAdapter(getAdapter());
        return processor;
    }
}
配置示例
xml 复制代码
<!-- BIO 连接器配置 -->
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           maxThreads="200"
           minSpareThreads="10"
           maxSpareThreads="50"
           acceptCount="100" />

4.2.2 NIO(非阻塞 I/O)

特点
  • 非阻塞模式:使用事件驱动模型
  • 高并发:少量线程处理大量连接
  • 复杂实现:需要处理事件循环和状态管理
  • 适用场景:高并发、长连接的应用
实现原理
java 复制代码
// NIO 连接器实现
public class Http11NioProtocol extends AbstractHttp11Protocol<NioChannel> {
    @Override
    protected AbstractEndpoint.Handler<NioChannel> getHandler() {
        return new Http11ConnectionHandler(this);
    }
}

// NIO 连接处理器
public class Http11ConnectionHandler extends AbstractConnectionHandler<NioChannel, Http11NioProcessor> {
    @Override
    protected Http11NioProcessor createProcessor() {
        Http11NioProcessor processor = new Http11NioProcessor(this);
        processor.setAdapter(getAdapter());
        return processor;
    }
}
事件循环
java 复制代码
// NIO 事件循环
public class Poller implements Runnable {
    private final Selector selector;
    private final AtomicBoolean running = new AtomicBoolean(true);
    
    @Override
    public void run() {
        while (running.get()) {
            try {
                // 等待事件
                int keyCount = selector.select(selectorTimeout);
                
                if (keyCount > 0) {
                    // 处理就绪的通道
                    Iterator<SelectionKey> iterator = 
                            selector.selectedKeys().iterator();
                    while (iterator.hasNext()) {
                        SelectionKey key = iterator.next();
                        iterator.remove();
                        
                        // 处理 I/O 事件
                        processKey(key);
                    }
                }
            } catch (Exception e) {
                // 处理异常
            }
        }
    }
    
    private void processKey(SelectionKey key) {
        if (key.isReadable()) {
            // 处理读事件
            processRead(key);
        } else if (key.isWritable()) {
            // 处理写事件
            processWrite(key);
        }
    }
}
配置示例
xml 复制代码
<!-- NIO 连接器配置 -->
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
           connectionTimeout="20000"
           maxThreads="200"
           minSpareThreads="10"
           maxSpareThreads="50"
           acceptCount="100"
           maxConnections="8192" />

4.2.3 NIO2(AIO - 异步 I/O)

特点
  • 异步模式:真正的异步 I/O 操作
  • 回调机制:使用 CompletionHandler 处理结果
  • 系统支持:需要操作系统支持异步 I/O
  • 适用场景:高并发、异步处理的应用
实现原理
java 复制代码
// NIO2 连接器实现
public class Http11Nio2Protocol extends AbstractHttp11Protocol<Nio2Channel> {
    @Override
    protected AbstractEndpoint.Handler<Nio2Channel> getHandler() {
        return new Http11ConnectionHandler(this);
    }
}

// NIO2 连接处理器
public class Http11ConnectionHandler extends AbstractConnectionHandler<Nio2Channel, Http11Nio2Processor> {
    @Override
    protected Http11Nio2Processor createProcessor() {
        Http11Nio2Processor processor = new Http11Nio2Processor(this);
        processor.setAdapter(getAdapter());
        return processor;
    }
}
异步处理
java 复制代码
// 异步 I/O 处理
public class Http11Nio2Processor extends AbstractProcessorLight {
    @Override
    public SocketState service(SocketWrapperBase<Nio2Channel> socketWrapper) 
            throws IOException {
        // 异步读取
        socketWrapper.getSocket().read(
            inputBuffer, 
            inputBuffer.position(), 
            inputBuffer.remaining(), 
            new CompletionHandler<Integer, Void>() {
                @Override
                public void completed(Integer result, Void attachment) {
                    // 处理读取结果
                    processRead(result);
                }
                
                @Override
                public void failed(Throwable exc, Void attachment) {
                    // 处理读取失败
                    processError(exc);
                }
            }
        );
        
        return SocketState.OPEN;
    }
}
配置示例
xml 复制代码
<!-- NIO2 连接器配置 -->
<Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
           connectionTimeout="20000"
           maxThreads="200"
           minSpareThreads="10"
           maxSpareThreads="50"
           acceptCount="100" />

4.2.4 APR(Apache Portable Runtime)

特点
  • 原生实现:使用 C 语言实现,性能更高
  • 系统优化:利用操作系统特性
  • 依赖库:需要安装 APR 库
  • 适用场景:对性能要求极高的应用
实现原理
java 复制代码
// APR 连接器实现
public class Http11AprProtocol extends AbstractHttp11Protocol<Long> {
    @Override
    protected AbstractEndpoint.Handler<Long> getHandler() {
        return new Http11ConnectionHandler(this);
    }
}

// APR 连接处理器
public class Http11ConnectionHandler extends AbstractConnectionHandler<Long, Http11AprProcessor> {
    @Override
    protected Http11AprProcessor createProcessor() {
        Http11AprProcessor processor = new Http11AprProcessor(this);
        processor.setAdapter(getAdapter());
        return processor;
    }
}
配置示例
xml 复制代码
<!-- APR 连接器配置 -->
<Connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol"
           connectionTimeout="20000"
           maxThreads="200"
           minSpareThreads="10"
           maxSpareThreads="50"
           acceptCount="100" />

4.3 线程生命周期管理

4.3.1 线程创建

线程工厂
java 复制代码
// 自定义线程工厂
public class TomcatThreadFactory implements ThreadFactory {
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;
    private final ThreadGroup group;
    private final boolean daemon;
    private final int priority;
    
    public TomcatThreadFactory(String namePrefix) {
        this(namePrefix, false, Thread.NORM_PRIORITY);
    }
    
    public TomcatThreadFactory(String namePrefix, boolean daemon, int priority) {
        this.namePrefix = namePrefix;
        this.daemon = daemon;
        this.priority = priority;
        this.group = Thread.currentThread().getThreadGroup();
    }
    
    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement());
        t.setDaemon(daemon);
        t.setPriority(priority);
        return t;
    }
}
线程创建流程
java 复制代码
// 线程创建流程
public class StandardThreadExecutor implements Executor {
    @Override
    public void execute(Runnable command) {
        // 1. 检查线程池状态
        if (executor.isShutdown()) {
            return;
        }
        
        // 2. 提交任务
        executor.execute(command);
    }
    
    private void createWorkerThread(Runnable command) {
        // 1. 创建线程
        Thread worker = threadFactory.newThread(command);
        
        // 2. 设置线程属性
        worker.setDaemon(false);
        worker.setPriority(Thread.NORM_PRIORITY);
        
        // 3. 启动线程
        worker.start();
    }
}

4.3.2 线程调度

任务调度
java 复制代码
// 任务调度器
public class TaskScheduler {
    private final ScheduledExecutorService scheduler;
    private final Map<String, ScheduledFuture<?>> tasks;
    
    public TaskScheduler() {
        this.scheduler = Executors.newScheduledThreadPool(1);
        this.tasks = new ConcurrentHashMap<>();
    }
    
    public void scheduleTask(String name, Runnable task, long delay, TimeUnit unit) {
        ScheduledFuture<?> future = scheduler.schedule(task, delay, unit);
        tasks.put(name, future);
    }
    
    public void scheduleAtFixedRate(String name, Runnable task, 
                                   long initialDelay, long period, TimeUnit unit) {
        ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(
            task, initialDelay, period, unit);
        tasks.put(name, future);
    }
    
    public void cancelTask(String name) {
        ScheduledFuture<?> future = tasks.remove(name);
        if (future != null) {
            future.cancel(false);
        }
    }
}
线程池监控
java 复制代码
// 线程池监控
public class ThreadPoolMonitor {
    private final ThreadPoolExecutor executor;
    private final ScheduledExecutorService monitor;
    
    public ThreadPoolMonitor(ThreadPoolExecutor executor) {
        this.executor = executor;
        this.monitor = Executors.newScheduledThreadPool(1);
        
        // 启动监控
        startMonitoring();
    }
    
    private void startMonitoring() {
        monitor.scheduleAtFixedRate(() -> {
            // 监控线程池状态
            int activeCount = executor.getActiveCount();
            int poolSize = executor.getPoolSize();
            int corePoolSize = executor.getCorePoolSize();
            int maximumPoolSize = executor.getMaximumPoolSize();
            long completedTaskCount = executor.getCompletedTaskCount();
            long taskCount = executor.getTaskCount();
            
            // 记录监控信息
            log.info("ThreadPool Status: active={}, pool={}, core={}, max={}, completed={}, total={}",
                    activeCount, poolSize, corePoolSize, maximumPoolSize, completedTaskCount, taskCount);
            
        }, 0, 30, TimeUnit.SECONDS);
    }
}

4.3.3 线程销毁

优雅关闭
java 复制代码
// 优雅关闭
public class GracefulShutdown {
    private final ThreadPoolExecutor executor;
    private final long timeout;
    private final TimeUnit unit;
    
    public GracefulShutdown(ThreadPoolExecutor executor, long timeout, TimeUnit unit) {
        this.executor = executor;
        this.timeout = timeout;
        this.unit = unit;
    }
    
    public void shutdown() {
        // 1. 停止接受新任务
        executor.shutdown();
        
        try {
            // 2. 等待现有任务完成
            if (!executor.awaitTermination(timeout, unit)) {
                // 3. 强制关闭
                executor.shutdownNow();
                
                // 4. 再次等待
                if (!executor.awaitTermination(timeout, unit)) {
                    log.warn("Thread pool did not terminate gracefully");
                }
            }
        } catch (InterruptedException e) {
            // 5. 中断当前线程
            executor.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}
资源清理
java 复制代码
// 资源清理
public class ResourceCleanup {
    private final List<AutoCloseable> resources;
    
    public ResourceCleanup() {
        this.resources = new ArrayList<>();
    }
    
    public void addResource(AutoCloseable resource) {
        resources.add(resource);
    }
    
    public void cleanup() {
        for (AutoCloseable resource : resources) {
            try {
                resource.close();
            } catch (Exception e) {
                log.error("Error closing resource", e);
            }
        }
        resources.clear();
    }
}

4.4 运行模式详解

4.4.1 独立运行模式

启动脚本
bash 复制代码
#!/bin/bash
# startup.sh

# 设置环境变量
export CATALINA_HOME="/opt/tomcat"
export CATALINA_BASE="/opt/tomcat"
export JAVA_HOME="/opt/java"
export JAVA_OPTS="-Xms512m -Xmx1024m -XX:PermSize=128m"

# 启动 Tomcat
exec "$CATALINA_HOME/bin/catalina.sh" run
停止脚本
bash 复制代码
#!/bin/bash
# shutdown.sh

# 设置环境变量
export CATALINA_HOME="/opt/tomcat"
export CATALINA_BASE="/opt/tomcat"

# 停止 Tomcat
exec "$CATALINA_HOME/bin/catalina.sh" stop
配置管理
xml 复制代码
<!-- 独立运行配置 -->
<Server port="8005" shutdown="SHUTDOWN">
    <Service name="Catalina">
        <Connector port="8080" protocol="HTTP/1.1"
                   connectionTimeout="20000"
                   redirectPort="8443" />
        <Engine name="Catalina" defaultHost="localhost">
            <Host name="localhost" appBase="webapps"
                  unpackWARs="true" autoDeploy="true">
                <Context path="/myapp" docBase="myapp" />
            </Host>
        </Engine>
    </Service>
</Server>

4.4.2 内嵌运行模式

Spring Boot 集成
java 复制代码
// Spring Boot 应用
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

// 自定义 Tomcat 配置
@Configuration
public class TomcatConfig {
    @Bean
    public TomcatServletWebServerFactory tomcatFactory() {
        return new TomcatServletWebServerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                // 自定义配置
                context.addParameter("app.config", "production");
            }
        };
    }
}
内嵌配置
java 复制代码
// 内嵌 Tomcat 配置
public class EmbeddedTomcatConfig {
    public static void main(String[] args) throws Exception {
        // 创建 Tomcat 实例
        Tomcat tomcat = new Tomcat();
        tomcat.setPort(8080);
        
        // 设置基础目录
        tomcat.setBaseDir(".");
        
        // 添加上下文
        Context context = tomcat.addContext("/myapp", ".");
        
        // 添加 Servlet
        Tomcat.addServlet(context, "MyServlet", new MyServlet());
        context.addServletMappingDecoded("/myservlet", "MyServlet");
        
        // 启动 Tomcat
        tomcat.start();
        tomcat.getServer().await();
    }
}

4.4.3 反向代理模式

Nginx 配置
nginx 复制代码
# nginx.conf
upstream tomcat_backend {
    server 127.0.0.1:8080 weight=1;
    server 127.0.0.1:8081 weight=1;
    server 127.0.0.1:8082 weight=1;
}

server {
    listen 80;
    server_name example.com;
    
    location / {
        proxy_pass http://tomcat_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    
    location /static/ {
        alias /var/www/static/;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}
负载均衡配置
java 复制代码
// 负载均衡配置
public class LoadBalancerConfig {
    private final List<Server> servers;
    private final AtomicInteger currentIndex;
    
    public LoadBalancerConfig(List<Server> servers) {
        this.servers = servers;
        this.currentIndex = new AtomicInteger(0);
    }
    
    public Server getNextServer() {
        int index = currentIndex.getAndIncrement() % servers.size();
        return servers.get(index);
    }
}

4.5 性能对比分析

4.5.1 I/O 模式性能对比

性能测试结果
I/O 模式 并发连接数 响应时间 吞吐量 内存使用 CPU 使用
BIO 1000 50ms 1000 req/s
NIO 10000 30ms 5000 req/s
NIO2 10000 25ms 6000 req/s
APR 10000 20ms 8000 req/s
性能分析
java 复制代码
// 性能测试代码
public class PerformanceTest {
    public void testBIO() {
        // BIO 性能测试
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            // 发送请求
            sendRequest();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("BIO Time: " + (endTime - startTime) + "ms");
    }
    
    public void testNIO() {
        // NIO 性能测试
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            // 发送请求
            sendRequest();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("NIO Time: " + (endTime - startTime) + "ms");
    }
}

4.5.2 线程模型性能对比

线程数量对比
java 复制代码
// 线程数量统计
public class ThreadCountMonitor {
    public void monitorThreads() {
        // 获取线程信息
        ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
        int threadCount = threadBean.getThreadCount();
        int peakThreadCount = threadBean.getPeakThreadCount();
        long totalStartedThreadCount = threadBean.getTotalStartedThreadCount();
        
        System.out.println("Thread Count: " + threadCount);
        System.out.println("Peak Thread Count: " + peakThreadCount);
        System.out.println("Total Started Thread Count: " + totalStartedThreadCount);
    }
}
内存使用对比
java 复制代码
// 内存使用监控
public class MemoryMonitor {
    public void monitorMemory() {
        MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
        MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
        MemoryUsage nonHeapUsage = memoryBean.getNonHeapMemoryUsage();
        
        System.out.println("Heap Used: " + heapUsage.getUsed() / 1024 / 1024 + "MB");
        System.out.println("Heap Max: " + heapUsage.getMax() / 1024 / 1024 + "MB");
        System.out.println("Non-Heap Used: " + nonHeapUsage.getUsed() / 1024 / 1024 + "MB");
    }
}

4.6 配置优化建议

4.6.1 线程池优化

核心参数配置
xml 复制代码
<!-- 线程池优化配置 -->
<Connector port="8080" protocol="HTTP/1.1"
           maxThreads="200"
           minSpareThreads="10"
           maxSpareThreads="50"
           acceptCount="100"
           connectionTimeout="20000"
           keepAliveTimeout="60000"
           maxKeepAliveRequests="100" />
参数说明
参数 说明 推荐值 调优建议
maxThreads 最大线程数 200-500 根据 CPU 核心数调整
minSpareThreads 最小空闲线程数 10-50 保证快速响应
maxSpareThreads 最大空闲线程数 50-100 避免资源浪费
acceptCount 等待队列长度 100-200 根据并发量调整
connectionTimeout 连接超时时间 20000ms 根据网络环境调整
keepAliveTimeout 保持连接时间 60000ms 根据应用特性调整

4.6.2 内存优化

JVM 参数配置
bash 复制代码
# JVM 参数优化
export JAVA_OPTS="-Xms512m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=256m -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
参数说明
参数 说明 推荐值 调优建议
-Xms 初始堆大小 512m 与 -Xmx 相同
-Xmx 最大堆大小 1024m-2048m 根据应用需求调整
-XX:PermSize 永久代初始大小 128m Java 8 之前使用
-XX:MaxPermSize 永久代最大大小 256m Java 8 之前使用
-XX:MetaspaceSize 元空间初始大小 128m Java 8 及以后使用
-XX:MaxMetaspaceSize 元空间最大大小 256m Java 8 及以后使用

4.6.3 系统优化

系统参数配置
bash 复制代码
# 系统参数优化
# 文件句柄数
ulimit -n 65536

# 网络参数
echo 'net.core.somaxconn = 65536' >> /etc/sysctl.conf
echo 'net.core.netdev_max_backlog = 5000' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_max_syn_backlog = 65536' >> /etc/sysctl.conf

# 应用参数
sysctl -p
参数说明
参数 说明 推荐值 调优建议
ulimit -n 文件句柄数 65536 根据连接数调整
somaxconn 监听队列长度 65536 提高并发处理能力
netdev_max_backlog 网络设备队列长度 5000 提高网络处理能力
tcp_max_syn_backlog TCP 连接队列长度 65536 提高 TCP 处理能力

4.7 本章小结

关键要点

  1. 线程模型

    • Acceptor 线程:接受新连接
    • Poller 线程:处理 I/O 事件
    • Worker 线程:处理业务逻辑
  2. I/O 模式

    • BIO:阻塞 I/O,简单但性能较低
    • NIO:非阻塞 I/O,高并发处理
    • NIO2:异步 I/O,真正的异步处理
    • APR:原生实现,性能最高
  3. 运行模式

    • 独立运行:传统部署方式
    • 内嵌运行:Spring Boot 集成
    • 反向代理:Nginx + Tomcat 架构
  4. 性能优化

    • 合理配置线程池参数
    • 优化 JVM 参数
    • 调整系统参数

选择建议

  1. 开发环境:使用 NIO 模式,配置简单
  2. 测试环境:使用 NIO 模式,性能适中
  3. 生产环境:使用 APR 模式,性能最优
  4. 高并发场景:使用 NIO2 模式,异步处理

下一步学习

在下一章中,我们将深入探讨 Tomcat 的配置体系与部署机制,了解各种配置文件的用途和配置方法,以及如何实现自动化部署和运维管理。


相关资源

相关推荐
黑马源码库miui520864 小时前
场馆预定系统小程序
微信·微信小程序·小程序·1024程序员节
小陈爱建模4 小时前
2025妈妈杯大数据竞赛A题mathorcup大数据:集装箱智能破损检测问题手把手思路代码文章教学大学生数学建模
数学建模·1024程序员节
兰亭妙微4 小时前
2026年UX/UI五大趋势:AI、AR与包容性设计将重新定义用户体验
开发语言·ui·1024程序员节·界面设计·设计趋势
CodeMonkeyyy4 小时前
iOS 自定义TabBar Controller高度问题
1024程序员节
Kent Gu5 小时前
Qutatus读取FPGA内部程序
其他·1024程序员节
蜗牛沐雨5 小时前
详解C++中的字符串流
c++·1024程序员节
蜗牛沐雨5 小时前
详解C++中的流
c++·1024程序员节
重生之我是Java开发战士5 小时前
【Java EE】了解Spring Web MVC:请求与响应的全过程
spring boot·spring·java-ee·1024程序员节