第四章-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 的配置体系与部署机制,了解各种配置文件的用途和配置方法,以及如何实现自动化部署和运维管理。


相关资源

相关推荐
fangzhanpeng1684 天前
快速掌握C#语言基础知识点(1.基础数据类型)
开发语言·c#·1024程序员节
无己心6 天前
面向多平台 AI 搜索引擎的适配层架构设计
前端·人工智能·搜索引擎·ai·1024程序员节
u01030552712 天前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u01030552712 天前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝14 天前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u01030552714 天前
Java图像处理实战指南
人工智能·1024程序员节
u01030552715 天前
Java AWT鼠标事件全解析
人工智能·1024程序员节
u01030552717 天前
Java实用类应用精讲
人工智能·1024程序员节
u01030552717 天前
Java I/O核心操作实战
人工智能·1024程序员节
u01030552718 天前
ArrayList操作详解与实战应用
人工智能·1024程序员节