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
相关推荐
小怪吴吴16 小时前
idea 开发Android
android·java·intellij-idea
嘻嘻哈哈樱桃16 小时前
牛客经典101题题解集--动态规划
java·数据结构·python·算法·职场和发展·动态规划
一次旅行16 小时前
IDEA安装CC GUI新手指南
java·ide·intellij-idea
超梦dasgg16 小时前
Spring AI 智能航空助手项目实战
java·人工智能·后端·spring·ai编程
counting money17 小时前
Spring框架基础(配置篇)
java·后端·spring
秋917 小时前
OceanBase与GreatSQL在Java应用中的性能调优方法有哪些?
java·开发语言·oceanbase
今天又在写代码17 小时前
并发问题解决
java·开发语言·数据库
老王以为17 小时前
前端视角下的 Java
java·javascript·程序员
看腻了那片水18 小时前
开源一个对业务代码零侵入的透明数据治理框架 —— 【sangsang】
java·mybatis