MINA框架面试题 - 实战篇

1. 使用MINA实现一个完整的聊天室服务器

答案:

这是一个包含用户管理、消息广播、私聊功能的完整聊天室实现。

服务端实现

java 复制代码
// 消息协议
public class ChatMessage implements Serializable {
    private String type;      // LOGIN, LOGOUT, PUBLIC, PRIVATE
    private String sender;
    private String receiver;  // 私聊接收者
    private String content;
    private long timestamp;
    
    // 构造函数和getter/setter省略
}

// 聊天室服务器
public class ChatServer {
    
    private static final int PORT = 9123;
    private static final Map<String, IoSession> users = 
        new ConcurrentHashMap<>();
    
    public static void main(String[] args) throws Exception {
        NioSocketAcceptor acceptor = new NioSocketAcceptor();
        
        // 配置
        acceptor.getSessionConfig().setReadBufferSize(2048);
        acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 300);
        
        // 过滤器链
        acceptor.getFilterChain().addLast("logger", 
            new LoggingFilter());
        acceptor.getFilterChain().addLast("codec", 
            new ProtocolCodecFilter(
                new ObjectSerializationCodecFactory()));
        
        // 业务处理器
        acceptor.setHandler(new ChatServerHandler());
        
        acceptor.bind(new InetSocketAddress(PORT));
        System.out.println("聊天服务器启动在端口: " + PORT);
    }
    
    // 聊天服务器处理器
    static class ChatServerHandler extends IoHandlerAdapter {
        
        @Override
        public void sessionCreated(IoSession session) throws Exception {
            System.out.println("新连接: " + session.getRemoteAddress());
        }
        
        @Override
        public void messageReceived(IoSession session, Object message) 
                throws Exception {
            
            ChatMessage msg = (ChatMessage) message;
            
            switch (msg.getType()) {
                case "LOGIN":
                    handleLogin(session, msg);
                    break;
                case "LOGOUT":
                    handleLogout(session, msg);
                    break;
                case "PUBLIC":
                    handlePublicMessage(session, msg);
                    break;
                case "PRIVATE":
                    handlePrivateMessage(session, msg);
                    break;
                default:
                    session.write(createErrorMessage("未知消息类型"));
            }
        }
        
        private void handleLogin(IoSession session, ChatMessage msg) {
            String username = msg.getSender();
            
            // 检查用户名是否已存在
            if (users.containsKey(username)) {
                session.write(createErrorMessage("用户名已存在"));
                return;
            }
            
            // 注册用户
            users.put(username, session);
            session.setAttribute("username", username);
            
            // 通知所有用户
            ChatMessage notification = new ChatMessage();
            notification.setType("SYSTEM");
            notification.setContent(username + " 加入了聊天室");
            notification.setTimestamp(System.currentTimeMillis());
            
            broadcast(notification, null);
            
            // 发送欢迎消息
            ChatMessage welcome = new ChatMessage();
            welcome.setType("SYSTEM");
            welcome.setContent("欢迎 " + username + "! 当前在线: " 
                + users.size() + " 人");
            session.write(welcome);
            
            // 发送在线用户列表
            sendUserList(session);
        }
        
        private void handleLogout(IoSession session, ChatMessage msg) {
            String username = (String) session.getAttribute("username");
            if (username != null) {
                users.remove(username);
                
                ChatMessage notification = new ChatMessage();
                notification.setType("SYSTEM");
                notification.setContent(username + " 离开了聊天室");
                notification.setTimestamp(System.currentTimeMillis());
                
                broadcast(notification, session);
            }
        }
        
        private void handlePublicMessage(IoSession session, ChatMessage msg) {
            String username = (String) session.getAttribute("username");
            if (username == null) {
                session.write(createErrorMessage("请先登录"));
                return;
            }
            
            msg.setSender(username);
            msg.setTimestamp(System.currentTimeMillis());
            broadcast(msg, null);
        }
        
        private void handlePrivateMessage(IoSession session, ChatMessage msg) {
            String username = (String) session.getAttribute("username");
            if (username == null) {
                session.write(createErrorMessage("请先登录"));
                return;
            }
            
            IoSession receiverSession = users.get(msg.getReceiver());
            if (receiverSession == null) {
                session.write(createErrorMessage("用户 " + msg.getReceiver() 
                    + " 不在线"));
                return;
            }
            
            msg.setSender(username);
            msg.setTimestamp(System.currentTimeMillis());
            receiverSession.write(msg);
            
            // 给发送者确认
            ChatMessage confirm = new ChatMessage();
            confirm.setType("SYSTEM");
            confirm.setContent("已发送给 " + msg.getReceiver());
            session.write(confirm);
        }
        
        private void broadcast(ChatMessage message, IoSession exclude) {
            for (IoSession session : users.values()) {
                if (session != exclude && session.isConnected()) {
                    session.write(message);
                }
            }
        }
        
        private void sendUserList(IoSession session) {
            ChatMessage userList = new ChatMessage();
            userList.setType("USER_LIST");
            userList.setContent(String.join(",", users.keySet()));
            session.write(userList);
        }
        
        private ChatMessage createErrorMessage(String error) {
            ChatMessage msg = new ChatMessage();
            msg.setType("ERROR");
            msg.setContent(error);
            msg.setTimestamp(System.currentTimeMillis());
            return msg;
        }
        
        @Override
        public void sessionClosed(IoSession session) throws Exception {
            String username = (String) session.getAttribute("username");
            if (username != null) {
                users.remove(username);
                
                ChatMessage notification = new ChatMessage();
                notification.setType("SYSTEM");
                notification.setContent(username + " 断开连接");
                notification.setTimestamp(System.currentTimeMillis());
                
                broadcast(notification, session);
            }
        }
        
        @Override
        public void sessionIdle(IoSession session, IdleStatus status) 
                throws Exception {
            System.out.println("连接空闲,关闭: " + session.getRemoteAddress());
            session.closeNow();
        }
        
        @Override
        public void exceptionCaught(IoSession session, Throwable cause) 
                throws Exception {
            cause.printStackTrace();
            session.closeNow();
        }
    }
}

客户端实现

java 复制代码
public class ChatClient {
    
    private IoSession session;
    private String username;
    
    public void connect(String host, int port, String username) 
            throws Exception {
        this.username = username;
        
        NioSocketConnector connector = new NioSocketConnector();
        
        connector.getFilterChain().addLast("codec", 
            new ProtocolCodecFilter(
                new ObjectSerializationCodecFactory()));
        
        connector.setHandler(new ChatClientHandler());
        
        ConnectFuture future = connector.connect(
            new InetSocketAddress(host, port)
        );
        future.awaitUninterruptibly();
        
        session = future.getSession();
        
        // 发送登录消息
        ChatMessage loginMsg = new ChatMessage();
        loginMsg.setType("LOGIN");
        loginMsg.setSender(username);
        session.write(loginMsg);
    }
    
    public void sendPublicMessage(String content) {
        ChatMessage msg = new ChatMessage();
        msg.setType("PUBLIC");
        msg.setContent(content);
        session.write(msg);
    }
    
    public void sendPrivateMessage(String receiver, String content) {
        ChatMessage msg = new ChatMessage();
        msg.setType("PRIVATE");
        msg.setReceiver(receiver);
        msg.setContent(content);
        session.write(msg);
    }
    
    public void disconnect() {
        if (session != null) {
            ChatMessage logoutMsg = new ChatMessage();
            logoutMsg.setType("LOGOUT");
            session.write(logoutMsg).awaitUninterruptibly();
            session.closeNow();
        }
    }
    
    // 客户端处理器
    class ChatClientHandler extends IoHandlerAdapter {
        
        @Override
        public void messageReceived(IoSession session, Object message) 
                throws Exception {
            ChatMessage msg = (ChatMessage) message;
            
            switch (msg.getType()) {
                case "SYSTEM":
                    System.out.println("[系统] " + msg.getContent());
                    break;
                case "PUBLIC":
                    System.out.println("[" + msg.getSender() + "] " 
                        + msg.getContent());
                    break;
                case "PRIVATE":
                    System.out.println("[私聊-" + msg.getSender() + "] " 
                        + msg.getContent());
                    break;
                case "USER_LIST":
                    System.out.println("[在线用户] " + msg.getContent());
                    break;
                case "ERROR":
                    System.out.println("[错误] " + msg.getContent());
                    break;
            }
        }
        
        @Override
        public void exceptionCaught(IoSession session, Throwable cause) 
                throws Exception {
            cause.printStackTrace();
        }
    }
}

功能特点:

  • 用户登录/登出管理
  • 公共消息广播
  • 私聊功能
  • 在线用户列表
  • 连接空闲检测
  • 异常处理

2. 如何在生产环境中优化MINA服务器的性能?

答案:

1. 线程池优化

java 复制代码
// 自定义IoProcessor线程池
int processorCount = Runtime.getRuntime().availableProcessors() * 2;
NioSocketAcceptor acceptor = new NioSocketAcceptor(processorCount);

// 添加业务线程池,避免阻塞I/O线程
ThreadPoolExecutor businessExecutor = new ThreadPoolExecutor(
    20,                           // 核心线程数
    100,                          // 最大线程数
    60L,                          // 空闲超时
    TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(1000),  // 队列大小
    new ThreadPoolExecutor.CallerRunsPolicy()  // 拒绝策略
);

ExecutorFilter executorFilter = new ExecutorFilter(businessExecutor);
acceptor.getFilterChain().addLast("executor", executorFilter);

2. 缓冲区优化

java 复制代码
SocketSessionConfig config = acceptor.getSessionConfig();

// 优化缓冲区大小
config.setReadBufferSize(8192);        // 8KB读缓冲
config.setReceiveBufferSize(65536);    // 64KB接收缓冲
config.setSendBufferSize(65536);       // 64KB发送缓冲

// 启用TCP_NODELAY,减少延迟
config.setTcpNoDelay(true);

// 启用SO_KEEPALIVE
config.setKeepAlive(true);

// 设置SO_REUSEADDR
config.setReuseAddress(true);

3. 内存管理优化

java 复制代码
// 使用直接内存
IoBuffer.setUseDirectBuffer(true);

// 启用内存池
IoBuffer.setAllocator(new CachedBufferAllocator());

// 自定义缓冲区分配器
public class CustomBufferAllocator implements IoBufferAllocator {
    private final Queue<IoBuffer> pool = new ConcurrentLinkedQueue<>();
    private final int bufferSize = 8192;
    private final int maxPoolSize = 1000;
    
    @Override
    public IoBuffer allocate(int capacity, boolean direct) {
        if (capacity == bufferSize) {
            IoBuffer buffer = pool.poll();
            if (buffer != null) {
                buffer.clear();
                return buffer;
            }
        }
        return IoBuffer.allocate(capacity, direct);
    }
    
    public void release(IoBuffer buffer) {
        if (buffer.capacity() == bufferSize && pool.size() < maxPoolSize) {
            pool.offer(buffer);
        }
    }
}

4. 编解码优化

java 复制代码
// 使用高效的序列化方式
// 避免使用Java原生序列化,推荐Protobuf、Kryo等

// Kryo编解码器示例
public class KryoCodecFactory implements ProtocolCodecFactory {
    
    @Override
    public ProtocolEncoder getEncoder(IoSession session) {
        return new KryoEncoder();
    }
    
    @Override
    public ProtocolDecoder getDecoder(IoSession session) {
        return new KryoDecoder();
    }
}

class KryoEncoder implements ProtocolEncoder {
    private final Kryo kryo = new Kryo();
    
    @Override
    public void encode(IoSession session, Object message, 
            ProtocolEncoderOutput out) throws Exception {
        
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        Output output = new Output(baos);
        
        kryo.writeClassAndObject(output, message);
        output.close();
        
        byte[] bytes = baos.toByteArray();
        IoBuffer buffer = IoBuffer.allocate(bytes.length + 4);
        buffer.putInt(bytes.length);
        buffer.put(bytes);
        buffer.flip();
        
        out.write(buffer);
    }
    
    @Override
    public void dispose(IoSession session) {}
}

5. 连接管理优化

java 复制代码
// 限制最大连接数
public class ConnectionLimitFilter extends IoFilterAdapter {
    private final AtomicInteger count = new AtomicInteger(0);
    private final int maxConnections = 10000;
    
    @Override
    public void sessionCreated(NextFilter nextFilter, IoSession session) 
            throws Exception {
        if (count.incrementAndGet() > maxConnections) {
            count.decrementAndGet();
            session.closeNow();
            return;
        }
        nextFilter.sessionCreated(session);
    }
    
    @Override
    public void sessionClosed(NextFilter nextFilter, IoSession session) 
            throws Exception {
        count.decrementAndGet();
        nextFilter.sessionClosed(session);
    }
}

// 添加连接限制
acceptor.getFilterChain().addFirst("connectionLimit", 
    new ConnectionLimitFilter());

6. 监控和日志优化

java 复制代码
// 使用异步日志
acceptor.getFilterChain().addLast("logger", new LoggingFilter() {
    @Override
    public void sessionCreated(NextFilter nextFilter, IoSession session) 
            throws Exception {
        // 异步记录日志
        asyncLog("Session created: " + session.getId());
        nextFilter.sessionCreated(session);
    }
});

// 定期输出统计信息
ScheduledExecutorService scheduler = 
    Executors.newScheduledThreadPool(1);

scheduler.scheduleAtFixedRate(() -> {
    IoServiceStatistics stats = acceptor.getStatistics();
    System.out.println("当前连接数: " + acceptor.getManagedSessionCount());
    System.out.println("累计读取: " + stats.getReadBytes() + " bytes");
    System.out.println("累计写入: " + stats.getWrittenBytes() + " bytes");
    System.out.println("平均读取速率: " + 
        stats.getReadBytesThroughput() + " bytes/s");
}, 0, 60, TimeUnit.SECONDS);

7. JVM优化

bash 复制代码
# JVM启动参数
java -server \
  -Xms4g -Xmx4g \                    # 堆内存
  -XX:+UseG1GC \                     # 使用G1垃圾收集器
  -XX:MaxGCPauseMillis=200 \         # GC停顿时间目标
  -XX:+UseStringDeduplication \      # 字符串去重
  -XX:+AlwaysPreTouch \              # 预分配内存
  -XX:MaxDirectMemorySize=2g \       # 直接内存大小
  -XX:+HeapDumpOnOutOfMemoryError \  # OOM时dump堆
  -Dio.netty.leakDetectionLevel=advanced \
  -jar mina-server.jar

性能优化建议总结:

  1. 合理配置线程池大小
  2. 使用直接内存和内存池
  3. 选择高效的序列化方式
  4. 启用TCP_NODELAY减少延迟
  5. 实施连接数限制和流量控制
  6. 使用异步日志
  7. 定期监控和分析性能指标
  8. 压力测试找出瓶颈

3. MINA服务器的压测方案和性能指标

答案:

压测工具选择

1. Apache JMeter

xml 复制代码
<!-- JMeter测试计划配置 -->
<TestPlan>
  <ThreadGroup>
    <num_threads>1000</num_threads>      <!-- 并发用户数 -->
    <ramp_time>60</ramp_time>             <!-- 启动时间 -->
    <duration>300</duration>              <!-- 测试持续时间 -->
  </ThreadGroup>
</TestPlan>

2. 自定义压测客户端

java 复制代码
public class LoadTestClient {
    
    private static final String HOST = "localhost";
    private static final int PORT = 9123;
    private static final int CLIENT_COUNT = 1000;
    private static final int MESSAGES_PER_CLIENT = 1000;
    
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newFixedThreadPool(
            CLIENT_COUNT
        );
        
        CountDownLatch latch = new CountDownLatch(CLIENT_COUNT);
        AtomicLong totalTime = new AtomicLong(0);
        AtomicLong successCount = new AtomicLong(0);
        AtomicLong failureCount = new AtomicLong(0);
        
        long startTime = System.currentTimeMillis();
        
        // 启动客户端
        for (int i = 0; i < CLIENT_COUNT; i++) {
            final int clientId = i;
            executor.submit(() -> {
                try {
                    runClient(clientId, totalTime, successCount, 
                        failureCount);
                } catch (Exception e) {
                    e.printStackTrace();
                    failureCount.incrementAndGet();
                } finally {
                    latch.countDown();
                }
            });
        }
        
        // 等待所有客户端完成
        latch.await();
        
        long endTime = System.currentTimeMillis();
        long duration = endTime - startTime;
        
        // 输出统计结果
        System.out.println("========== 压测结果 ==========");
        System.out.println("客户端数量: " + CLIENT_COUNT);
        System.out.println("总请求数: " + 
            (CLIENT_COUNT * MESSAGES_PER_CLIENT));
        System.out.println("成功数: " + successCount.get());
        System.out.println("失败数: " + failureCount.get());
        System.out.println("总耗时: " + duration + "ms");
        System.out.println("TPS: " + 
            (successCount.get() * 1000 / duration));
        System.out.println("平均响应时间: " + 
            (totalTime.get() / successCount.get()) + "ms");
        
        executor.shutdown();
    }
    
    private static void runClient(int clientId, AtomicLong totalTime,
            AtomicLong successCount, AtomicLong failureCount) 
            throws Exception {
        
        NioSocketConnector connector = new NioSocketConnector();
        connector.getFilterChain().addLast("codec", 
            new ProtocolCodecFilter(new TextLineCodecFactory()));
        
        CountDownLatch msgLatch = new CountDownLatch(MESSAGES_PER_CLIENT);
        
        connector.setHandler(new IoHandlerAdapter() {
            @Override
            public void messageReceived(IoSession session, Object message) {
                msgLatch.countDown();
            }
        });
        
        ConnectFuture future = connector.connect(
            new InetSocketAddress(HOST, PORT)
        );
        future.awaitUninterruptibly();
        
        if (!future.isConnected()) {
            failureCount.addAndGet(MESSAGES_PER_CLIENT);
            return;
        }
        
        IoSession session = future.getSession();
        
        // 发送消息
        for (int i = 0; i < MESSAGES_PER_CLIENT; i++) {
            long start = System.currentTimeMillis();
            session.write("Client-" + clientId + ": Message-" + i);
            
            if (msgLatch.await(5, TimeUnit.SECONDS)) {
                totalTime.addAndGet(System.currentTimeMillis() - start);
                successCount.incrementAndGet();
            } else {
                failureCount.incrementAndGet();
            }
        }
        
        session.closeNow();
        connector.dispose();
    }
}

关键性能指标

1. TPS (Transactions Per Second)

java 复制代码
public class TPSMonitor {
    private AtomicLong counter = new AtomicLong(0);
    private long lastTime = System.currentTimeMillis();
    
    public void recordRequest() {
        counter.incrementAndGet();
    }
    
    public double getCurrentTPS() {
        long current = System.currentTimeMillis();
        long count = counter.getAndSet(0);
        long duration = current - lastTime;
        lastTime = current;
        
        return (count * 1000.0) / duration;
    }
}

2. 响应时间监控

java 复制代码
public class ResponseTimeMonitor {
    private final ConcurrentLinkedQueue<Long> responseTimes = 
        new ConcurrentLinkedQueue<>();
    
    public void recordResponseTime(long time) {
        responseTimes.offer(time);
        
        // 保持最近1000个样本
        while (responseTimes.size() > 1000) {
            responseTimes.poll();
        }
    }
    
    public Statistics getStatistics() {
        List<Long> times = new ArrayList<>(responseTimes);
        Collections.sort(times);
        
        double avg = times.stream()
            .mapToLong(Long::longValue)
            .average()
            .orElse(0);
        
        long p50 = times.get(times.size() / 2);
        long p95 = times.get((int) (times.size() * 0.95));
        long p99 = times.get((int) (times.size() * 0.99));
        
        return new Statistics(avg, p50, p95, p99);
    }
}

3. 资源使用监控

java 复制代码
public class ResourceMonitor {
    
    public void printSystemInfo() {
        Runtime runtime = Runtime.getRuntime();
        
        System.out.println("========== 系统资源 ==========");
        System.out.println("总内存: " + 
            (runtime.totalMemory() / 1024 / 1024) + "MB");
        System.out.println("空闲内存: " + 
            (runtime.freeMemory() / 1024 / 1024) + "MB");
        System.out.println("已用内存: " + 
            ((runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024) 
            + "MB");
        System.out.println("最大内存: " + 
            (runtime.maxMemory() / 1024 / 1024) + "MB");
        System.out.println("可用处理器: " + 
            runtime.availableProcessors());
        
        ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
        System.out.println("活跃线程数: " + threadBean.getThreadCount());
        System.out.println("峰值线程数: " + threadBean.getPeakThreadCount());
    }
}

压测建议:

  1. 逐步增加并发,找到系统临界点
  2. 长时间运行测试,发现内存泄漏
  3. 监控CPU、内存、网络I/O
  4. 分析慢查询和瓶颈点
  5. 进行极限压测,测试系统稳定性

4. MINA项目中常见的坑和解决方案

答案:

坑1: IoBuffer未flip导致数据读取失败

问题:

java 复制代码
// 错误示例
IoBuffer buffer = IoBuffer.allocate(100);
buffer.put("Hello".getBytes());
// 忘记flip,导致读取失败
out.write(buffer);

解决方案:

java 复制代码
// 正确做法
IoBuffer buffer = IoBuffer.allocate(100);
buffer.put("Hello".getBytes());
buffer.flip();  // 必须flip,切换到读模式
out.write(buffer);

坑2: Session属性内存泄漏

问题:

java 复制代码
// 在Session中存储大对象,忘记清理
session.setAttribute("largeData", new byte[10 * 1024 * 1024]);
// Session关闭后,属性没有被清理

解决方案:

java 复制代码
@Override
public void sessionClosed(IoSession session) throws Exception {
    // 清理所有属性
    session.removeAttribute("largeData");
    session.removeAttribute("userData");
    
    // 或者清空所有属性
    Set<Object> keys = session.getAttributeKeys();
    for (Object key : keys) {
        session.removeAttribute(key);
    }
}

坑3: 过滤器顺序错误

问题:

java 复制代码
// 错误:编解码器在日志过滤器之前
acceptor.getFilterChain().addLast("codec", codecFilter);
acceptor.getFilterChain().addLast("logger", loggingFilter);
// 导致日志记录的是编码后的字节,而不是业务对象

解决方案:

java 复制代码
// 正确顺序
acceptor.getFilterChain().addLast("logger", loggingFilter);
acceptor.getFilterChain().addLast("codec", codecFilter);
acceptor.getFilterChain().addLast("executor", executorFilter);

// SSL必须在最前面
acceptor.getFilterChain().addFirst("ssl", sslFilter);

坑4: 阻塞操作放在IoHandler中

问题:

java 复制代码
@Override
public void messageReceived(IoSession session, Object message) {
    // 错误:数据库查询阻塞I/O线程
    User user = database.queryUser(userId);  // 可能很慢
    session.write(user);
}

解决方案:

java 复制代码
// 方案1:使用ExecutorFilter
acceptor.getFilterChain().addLast("executor", 
    new ExecutorFilter(Executors.newCachedThreadPool()));

// 方案2:手动异步处理
@Override
public void messageReceived(IoSession session, Object message) {
    executor.submit(() -> {
        try {
            User user = database.queryUser(userId);
            session.write(user);
        } catch (Exception e) {
            session.write("查询失败");
        }
    });
}

坑5: 解码器中粘包处理不当

问题:

java 复制代码
// 错误:没有保存解码状态
@Override
protected boolean doDecode(IoSession session, IoBuffer in, 
        ProtocolDecoderOutput out) {
    if (in.remaining() < 4) {
        return false;  // 数据丢失,下次进来又从头开始
    }
    int length = in.getInt();
    // ...
}

解决方案:

java 复制代码
// 正确:使用mark和reset
@Override
protected boolean doDecode(IoSession session, IoBuffer in, 
        ProtocolDecoderOutput out) {
    in.mark();  // 标记当前位置
    
    if (in.remaining() < 4) {
        in.reset();  // 恢复到标记位置
        return false;
    }
    
    int length = in.getInt();
    
    if (in.remaining() < length) {
        in.reset();  // 数据不够,恢复位置
        return false;
    }
    
    byte[] data = new byte[length];
    in.get(data);
    out.write(data);
    
    return true;
}

坑6: 忘记处理异常

问题:

java 复制代码
// 没有实现exceptionCaught
public class MyHandler extends IoHandlerAdapter {
    // 异常被吞掉,难以排查问题
}

解决方案:

java 复制代码
@Override
public void exceptionCaught(IoSession session, Throwable cause) {
    // 记录日志
    logger.error("Session " + session.getId() + " error", cause);
    
    // 根据异常类型处理
    if (cause instanceof IOException) {
        // 网络异常,关闭连接
        session.close
相关推荐
数智工坊2 小时前
【操作系统-处理器调度】
java·linux·服务器·windows·ubuntu
Coder_Boy_2 小时前
基于SpringAI的在线考试系统-考试管理功能布局+交互优化方案
java·数据库·人工智能·spring boot·交互·ddd·tdd
Tao____2 小时前
可以本地部署的物联网平台
java·开发语言·物联网·mqtt·低代码
码界奇点2 小时前
基于DDD与CQRS的Java企业级应用框架设计与实现
java·开发语言·c++·毕业设计·源代码管理
柏林以东_2 小时前
线程安全的数据集合
java·开发语言·安全
进阶的猿猴2 小时前
java中实现markdown转为pdf
java·pdf·markdown
sunnyday04262 小时前
Nginx与Spring Cloud Gateway QPS统计全攻略
java·spring boot·后端·nginx
海南java第二人2 小时前
Spring Boot全局异常处理终极指南:打造优雅的API错误响应体系
java·spring boot·后端
南朝雨2 小时前
Spring Boot Admin日志监控坑点:远程配置的logging.file.name为何生效又失效?
java·spring boot·spring cloud·微服务·logback