轩辕李的博客 轩辕李的博客
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • HTML&CSS
  • JavaScript
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

轩辕李

勇猛精进,星辰大海
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • HTML&CSS
  • JavaScript
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Java

    • 核心

      • Java8--Lambda 表达式、Stream 和时间 API
      • Java集合
      • Java IO
      • Java 文件操作
      • Java 网络编程
        • 一、网络协议分层
        • 二、Socket编程
          • 1、传统IO(BIO)
          • 1.1、服务端实现
          • 1.2、客户端实现
          • 1.3、多客户端支持
          • 2、NIO(非阻塞IO)
          • 2.1、核心概念
          • 2.2、工作原理
          • 2.3、服务端实现
          • 2.4、客户端实现
          • 2.5、NIO的性能优化
          • 3、AIO(异步IO)
          • 3.1、vs NIO的区别
          • 3.2、服务端实现
          • 3.3、AIO的适用场景
          • 4、Netty
          • 4.1、为什么选择Netty
          • 4.2、Netty的核心架构
          • 5、高性能服务器的并发模型对比
          • 5.1、Nginx的并发模型
          • 5.2、vs Nginx:为什么设计不同?
        • 三、HTTP编程
          • 1、服务端
          • 1.1、主流框架推荐
          • 2、客户端
          • 2.1、HttpURLConnection(传统方式)
          • 2.2、HttpClient
          • 2.3、11 HTTP Client(现代方式)
          • a、代理设置详解
          • 2.4、声明式HTTP客户端
        • 四、总结
      • Java运行期动态能力
      • Java可插入注解处理器
      • Java基准测试(JMH)
      • Java性能分析(Profiler)
      • Java调试(JDI与JDWP)
      • Java管理与监控(JMX)
      • Java加密体系(JCA)
      • Java服务发现(SPI)
      • Java随机数生成研究
      • Java数据库连接(JDBC)
      • Java历代版本新特性
      • 写好Java Doc
      • 聊聊classpath及其资源获取
    • 并发

    • 经验

    • JVM

    • 企业应用

  • Spring

  • 其他语言

  • 工具

  • 后端
  • Java
  • 核心
轩辕李
2021-09-20
目录

Java 网络编程

在互联网时代,网络编程已经成为每个Java开发者必须掌握的核心技能。无论是开发Web应用、微服务,还是构建分布式系统,都离不开网络通信的支撑。

网络编程本质上是解决不同主机间程序如何通信的问题。Java从诞生之初就内置了强大的网络编程能力,从传统的Socket到现代的NIO、AIO,再到高性能框架Netty,技术栈在不断演进。

本文将系统介绍Java网络编程的核心技术,包括Socket编程和HTTP编程两大部分。如果你对IO基础还不太熟悉,建议先阅读Java IO。

# 一、网络协议分层

在深入Java网络编程之前,理解网络协议分层模型至关重要。网络通信是个复杂的过程,涉及数据的封装、传输、路由和解析等多个环节。为了降低复杂度并实现模块化设计,网络协议采用了分层架构: clipboard

在实际开发中,我们主要接触TCP/IP四层模型。每一层都有明确的职责分工:

  • 数据链路层:负责相邻网络设备(如路由器、交换机)之间的数据传输,处理物理地址(MAC地址)
  • 网络层:实现不同网络中主机之间的通信,使用IP地址进行寻址和路由选择
  • 传输层:为应用程序提供端到端的通信服务,主要协议有TCP(可靠传输)和UDP(高效传输)
  • 应用层:直接为用户应用提供服务,包括HTTP、FTP、SMTP等协议

作为Java开发者,我们主要在传输层(Socket编程)和应用层(HTTP编程)工作。

# 二、Socket编程

Socket(套接字)是网络编程的基础抽象,它代表了网络中两个程序通信的端点。可以把Socket理解为两个程序之间的"电话线"——一端说话,另一端就能听到。

Socket编程工作在传输层,直接使用TCP或UDP协议。在Java中,Socket编程经历了从传统阻塞IO到NIO、AIO的演进过程,每种模式都有其适用场景。

让我们通过一个简单的例子来理解:客户端发送消息"我要吃肉",服务端响应"地主家没有余粮了"。

# 1、传统IO(BIO)

传统的Socket编程采用阻塞IO(Blocking IO)模型。"阻塞"意味着当程序执行accept()或read()操作时,如果没有连接到来或数据可读,线程会一直等待,无法做其他事情。

# 1.1、服务端实现

void server(){
    try (ServerSocket server = new ServerSocket(8888)) {
        while (true){
            // accept()会阻塞等待客户端连接
            Socket socket = server.accept();
            
            // 获取输入输出流
            InputStream is = socket.getInputStream();
            OutputStream os = socket.getOutputStream();
            Scanner scanner = new Scanner(is);
            PrintWriter pw = new PrintWriter(
                new OutputStreamWriter(os, StandardCharsets.UTF_8), true);

            // 处理客户端消息
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                if (line.startsWith("我要吃肉")){
                    pw.println("地主家没有余粮了");
                }else {
                    pw.println("我不知道你在说什么");
                }
                if ("exit".equals(line)) {
                    pw.println("exit");
                    break;
                }
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

# 1.2、客户端实现

void client(){
    try (Socket socket = new Socket("localhost", 8888);
         InputStream is = socket.getInputStream();
         OutputStream outputStream = socket.getOutputStream()) {
        
        PrintWriter pw = new PrintWriter(
            new OutputStreamWriter(outputStream, StandardCharsets.UTF_8), true);
        Scanner scanner = new Scanner(is, StandardCharsets.UTF_8);
        
        // 发送消息到服务端
        pw.println("我要吃肉");
        pw.println("exit");
        
        // 接收服务端响应
        boolean done = false;
        while (!done && scanner.hasNextLine()) {
            String line = scanner.nextLine();
            System.out.println("服务端响应: " + line);
            if (line.equals("exit")){
                done = true;
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

# 1.3、多客户端支持

上面的服务端程序有个明显缺陷:只能为一个客户端服务。当一个客户端连接后,其他客户端必须等待。要支持多客户端并发访问,需要引入多线程:

// 使用线程池优化
ExecutorService executor = Executors.newFixedThreadPool(100);

try (ServerSocket server = new ServerSocket(8888)) {
    while (true) {
        Socket socket = server.accept();
        
        // 为每个客户端分配一个线程处理
        executor.submit(() -> {
            try {
                handleClient(socket);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    executor.shutdown();
}

这种"一个连接一个线程"的模式简单直观,但存在明显问题:

  • 资源消耗大:每个线程占用一定内存(通常1MB左右)
  • 上下文切换开销:线程数量过多时,CPU在线程间切换的开销很大
  • 扩展性差:系统能创建的线程数有限,难以支撑C10K(万级并发)场景

这些问题促使了NIO的诞生。

# 2、NIO(非阻塞IO)

Java 1.4引入的NIO(New IO)采用了完全不同的设计思路。与BIO的"一个连接一个线程"不同,NIO可以用一个线程管理多个连接。

# 2.1、核心概念

NIO的三大核心组件:

  • Channel(通道):双向的数据传输通道,相当于BIO中的Stream
  • Buffer(缓冲区):数据读写的中转站,所有数据都要经过Buffer
  • Selector(选择器):IO多路复用器,一个Selector可以监控多个Channel的事件

# 2.2、工作原理

NIO采用了Reactor模式,工作流程如下:

  1. 注册阶段:将Channel注册到Selector上,指定关注的事件(连接、读、写等)
  2. 轮询阶段:Selector通过select()方法轮询注册的Channel,这是唯一的阻塞点
  3. 处理阶段:当某个Channel就绪时,Selector返回就绪的Channel集合,逐个处理

这种模式的优势在于:一个线程可以管理成千上万个连接,极大提升了系统的并发能力。

# 2.3、服务端实现

void server() throws IOException {
    // 1. 创建Selector多路复用器
    Selector selector = Selector.open();

    // 2. 创建ServerSocketChannel并配置为非阻塞
    ServerSocketChannel ssChannel = ServerSocketChannel.open();
    ssChannel.configureBlocking(false);
    
    // 3. 注册到Selector,关注ACCEPT事件
    ssChannel.register(selector, SelectionKey.OP_ACCEPT);

    // 4. 绑定端口
    ServerSocket serverSocket = ssChannel.socket();
    InetSocketAddress address = new InetSocketAddress("127.0.0.1", 8888);
    serverSocket.bind(address);
    
    System.out.println("NIO服务器启动,监听端口:8888");
    
    while (true) {
        // 5. 阻塞等待就绪事件
        selector.select();
        
        // 6. 获取就绪的SelectionKey集合
        Set<SelectionKey> keys = selector.selectedKeys();
        Iterator<SelectionKey> keyIterator = keys.iterator();
        
        while (keyIterator.hasNext()) {
            SelectionKey key = keyIterator.next();
            
            if (key.isAcceptable()) {
                // 处理连接请求
                ServerSocketChannel ssChannel1 = (ServerSocketChannel) key.channel();
                SocketChannel sChannel = ssChannel1.accept();
                sChannel.configureBlocking(false);
                // 新连接注册READ事件
                sChannel.register(selector, SelectionKey.OP_READ);
                
            } else if (key.isReadable()) {
                // 处理读请求
                SocketChannel sChannel = (SocketChannel) key.channel();
                String line = readDataFromSocketChannel(sChannel);
                
                if (line.startsWith("我要吃肉")){
                    sChannel.write(StandardCharsets.UTF_8.encode("地主家没有余粮了"));
                }else {
                    sChannel.write(StandardCharsets.UTF_8.encode("我不知道你在说什么"));
                }
                sChannel.close();
            }
            
            // 移除已处理的key
            keyIterator.remove();
        }
    }
}

// 辅助方法:从Channel读取数据
private static String readDataFromSocketChannel(SocketChannel sChannel) throws IOException {
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    StringBuilder data = new StringBuilder();
    
    while (true) {
        buffer.clear();
        int n = sChannel.read(buffer);
        if (n <= 0) {
            break;
        }
        buffer.flip();  // 切换到读模式
        data.append(StandardCharsets.UTF_8.decode(buffer));
    }
    return data.toString();
}

# 2.4、客户端实现

NIO的客户端可以继续使用传统的阻塞方式,也可以采用非阻塞方式:

void client() throws IOException {
    Socket socket = new Socket("127.0.0.1", 8888);
    OutputStream out = socket.getOutputStream();
    out.write("我要吃肉".getBytes());
    
    Scanner scanner = new Scanner(socket.getInputStream(), StandardCharsets.UTF_8);
    while (scanner.hasNextLine()) {
        String line = scanner.nextLine();
        System.out.println("服务端响应: " + line);
    }
    out.close();
}

# 2.5、NIO的性能优化

有人可能会问:单线程处理所有请求,性能会不会成为瓶颈?

实际上,NIO可以结合线程池进一步优化性能。常见的做法是:

  • 主线程负责接收连接(Accept)
  • 工作线程池负责处理IO读写

这就是经典的主从Reactor模式,Netty等高性能框架都采用了这种设计。

# 3、AIO(异步IO)

NIO虽然是非阻塞的,但本质上还是同步IO——需要应用程序主动询问"数据好了吗"。Java 7引入的AIO(Asynchronous IO,也叫NIO.2)实现了真正的异步IO。

# 3.1、vs NIO的区别

  • NIO:应用程序需要不断询问OS"数据准备好了吗"(通过select()轮询)
  • AIO:应用程序告诉OS"数据好了叫我",然后就可以干别的事了(基于回调)

AIO采用了"订阅-通知"模式:

  1. 应用程序发起IO请求,并注册回调函数
  2. 应用程序继续执行其他任务,不用等待
  3. OS完成IO操作后,主动调用回调函数通知应用程序

# 3.2、服务端实现

public class AioSocketServer {
    static final InetSocketAddress address = new InetSocketAddress("127.0.0.1", 8888);
    private static final Object waitObject = new Object();

    void server() throws IOException, InterruptedException {
        // 创建异步服务端通道
        AsynchronousServerSocketChannel serverSock = 
            AsynchronousServerSocketChannel.open().bind(address);
        
        // 异步接受连接,注册回调
        serverSock.accept(serverSock, new CompletionHandler<>() {
            @Override
            public void completed(AsynchronousSocketChannel socketChannel, 
                                AsynchronousServerSocketChannel serverSock) {
                // 继续接受下一个连接
                serverSock.accept(serverSock, this);
                
                // 异步读取数据
                ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                socketChannel.read(byteBuffer, byteBuffer, 
                    new ReadCompletionHandler(socketChannel));
            }

            @Override
            public void failed(Throwable exc, AsynchronousServerSocketChannel attachment) {
                System.err.println("Accept failed: " + exc.getMessage());
            }
        });

        System.out.println("AIO服务器启动,监听端口:8888");
        
        // 保持主线程存活
        synchronized(waitObject) {
            waitObject.wait();
        }
    }

    // 读取完成的回调处理器
    class ReadCompletionHandler implements CompletionHandler<Integer, ByteBuffer> {
        private AsynchronousSocketChannel channel;
        
        public ReadCompletionHandler(AsynchronousSocketChannel channel) {
            this.channel = channel;
        }
        
        @Override
        public void completed(Integer result, ByteBuffer buffer) {
            if (result == -1) {
                try {
                    channel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return;
            }
            
            buffer.flip();
            String message = StandardCharsets.UTF_8.decode(buffer).toString();
            System.out.println("收到消息: " + message);
            
            // 处理业务逻辑并响应
            String response;
            if (message.startsWith("我要吃肉")) {
                response = "地主家没有余粮了";
            } else {
                response = "我不知道你在说什么";
            }
            
            // 异步写入响应
            channel.write(StandardCharsets.UTF_8.encode(response));
        }
        
        @Override
        public void failed(Throwable exc, ByteBuffer buffer) {
            System.err.println("Read failed: " + exc.getMessage());
        }
    }
}

# 3.3、AIO的适用场景

虽然AIO看起来很美好,但实际应用中却不如NIO普及,原因如下:

  1. 操作系统支持有限:Windows的IOCP支持良好,但Linux的AIO支持不完善
  2. 编程复杂度高:异步回调的编程模式容易造成"回调地狱"
  3. 性能提升有限:对比NIO,AIO的性能提升并不明显

因此,在实际项目中,NIO(特别是通过Netty封装后)仍然是主流选择。AIO更适合于:

  • Windows平台的高并发服务
  • 连接数不多但每个连接传输数据量大的场景
  • 需要真正异步处理的特殊业务场景

# 4、Netty

原生的NIO API虽然功能强大,但使用复杂、容易出错。实际项目中,我们通常会使用Netty这样的高性能网络框架。

# 4.1、为什么选择Netty

  1. 易用性高:屏蔽了NIO的复杂性,提供简洁的API
  2. 功能完善:内置了编解码器、心跳检测、流量控制等常用功能
  3. 性能卓越:零拷贝、内存池、无锁设计等优化手段
  4. 协议支持广泛:TCP、UDP、HTTP、WebSocket等协议开箱即用
  5. 社区活跃:被广泛应用于Dubbo、RocketMQ、Elasticsearch等知名项目

# 4.2、Netty的核心架构

Netty基于主从Reactor模式设计:

  • Boss Group:负责接收连接,相当于传统的Acceptor
  • Worker Group:负责处理IO事件,相当于IO处理线程池
  • ChannelPipeline:责任链模式,用于处理入站和出站事件
  • ChannelHandler:业务逻辑处理器

想深入学习Netty,推荐查看官方示例 (opens new window)和Netty权威指南 (opens new window)。

# 5、高性能服务器的并发模型对比

了解了Java的各种IO模型后,我们来对比一下业界主流高性能服务器的设计思路。

# 5.1、Nginx的并发模型

Nginx采用多进程+单线程+非阻塞IO的架构:

  • Master进程:负责管理Worker进程
  • Worker进程:每个进程内部采用单线程+epoll的方式处理请求
  • 优势:进程隔离性好,单个Worker崩溃不影响其他Worker
  • 适用场景:静态文件服务、反向代理、负载均衡等IO密集型任务

# 5.2、vs Nginx:为什么设计不同?

很多人疑惑:既然Nginx单线程就能处理高并发,为什么Netty和Tomcat还要用线程池?

关键在于应用场景的差异:

  1. 业务复杂度不同

    • Nginx:主要做转发和静态文件服务,CPU计算少
    • Netty/Tomcat:需要执行复杂的业务逻辑,CPU密集型操作多
  2. 编程语言特性

    • Nginx:C语言编写,没有GC,内存管理可控
    • Netty/Tomcat:Java编写,有GC停顿,需要考虑JVM特性
  3. 扩展性需求

    • Nginx:功能相对固定,通过配置和模块扩展
    • Netty/Tomcat:需要支持各种自定义业务逻辑

因此,Netty采用线程池是为了:

  • 充分利用多核CPU进行业务处理
  • 避免业务逻辑阻塞影响其他连接
  • 提供更好的扩展性和灵活性

# 三、HTTP编程

前面介绍的Socket编程属于传输层,而HTTP编程工作在应用层。HTTP协议基于TCP实现,为Web应用提供了标准的通信协议。

# 1、服务端

对于HTTP服务端开发,Java生态提供了丰富的选择:

# 1.1、主流框架推荐

  • Spring Boot WebFlux:响应式编程模型,适合高并发场景,推荐优先使用
  • Spring Boot Web MVC:传统的Servlet模型,生态成熟,适合常规Web应用
  • Netty HTTP Server:基于Netty的原生HTTP实现,性能极致但需要手动处理很多细节
  • Helidon:Oracle出品的云原生框架,轻量级、启动快

实际项目中,Spring Boot凭借其强大的生态系统和开发效率,是大多数团队的首选。

# 2、客户端

# 2.1、HttpURLConnection(传统方式)

在Java 11之前,HttpURLConnection是JDK内置的HTTP客户端:

String url = "https://www.baidu.com/";
URL obj = new URL(url);
HttpURLConnection connection = (HttpURLConnection) obj.openConnection();

// 设置请求属性
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);  // 连接超时
connection.setReadTimeout(5000);     // 读取超时

// 发起连接
connection.connect();

// 处理响应
int responseCode = connection.getResponseCode();
if(responseCode == HttpURLConnection.HTTP_OK){
    try (BufferedReader reader = new BufferedReader(
            new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
        String line;
        StringBuilder response = new StringBuilder();
        while ((line = reader.readLine()) != null) {
            response.append(line);
        }
        System.out.println(response.toString());
    }
}
connection.disconnect();

HttpURLConnection的缺点很明显:

  • API设计陈旧,使用繁琐
  • 不支持连接池,性能较差
  • 缺少现代HTTP特性支持(如HTTP/2)

# 2.2、HttpClient

业界广泛使用的是Apache HttpClient (opens new window),它提供了更强大的功能。

我个人推荐使用Unirest (opens new window),它基于Apache HttpClient封装,API更加简洁:

// 简洁的链式调用
HttpResponse<JsonNode> response = Unirest.post("http://localhost/post")
      .header("accept", "application/json")
      .queryString("apiKey", "123")
      .field("parameter", "value")
      .field("firstname", "Gary")
      .asJson();

// 处理响应
int status = response.getStatus();
JsonNode body = response.getBody();

Unirest支持灵活的配置管理:

// 全局配置(影响所有请求)
Unirest.config()
    .defaultBaseUrl("https://api.example.com")
    .connectTimeout(10000)
    .socketTimeout(30000)
    .proxy("127.0.0.1", 8888)
    .concurrency(200, 10);  // 连接池配置

// 创建独立实例(不影响全局)
UnirestInstance customClient = Unirest.spawnInstance();
customClient.config()
    .connectTimeout(5000)
    .socketTimeout(15000);

// 请求级配置(优先级最高)
HttpResponse<String> response = Unirest.get("https://example.com")
    .connectTimeout(3000)  // 覆盖全局配置
    .asString();

# 2.3、11 HTTP Client(现代方式)

Java 11引入的HttpClient是一个全新设计的HTTP客户端,支持HTTP/2和异步编程:

// 创建HttpClient
HttpClient client = HttpClient.newBuilder()
    .version(Version.HTTP_2)           // 支持HTTP/2
    .connectTimeout(Duration.ofSeconds(10))
    .proxy(ProxySelector.of(new InetSocketAddress("127.0.0.1", 8888)))
    .build();

// 构建请求
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.example.com/data"))
    .timeout(Duration.ofSeconds(30))
    .header("Content-Type", "application/json")
    .POST(BodyPublishers.ofString("{\"name\":\"test\"}"))
    .build();

// 同步请求
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
System.out.println("Status: " + response.statusCode());
System.out.println("Body: " + response.body());

// 异步请求
CompletableFuture<HttpResponse<String>> future = 
    client.sendAsync(request, BodyHandlers.ofString());
future.thenAccept(res -> System.out.println("Async response: " + res.body()));

HttpClient的优势:

  • 原生支持HTTP/2
  • 支持同步和异步编程
  • 内置连接池管理
  • 支持WebSocket
  • 更现代的API设计

如需自定义线程池:

ExecutorService executor = Executors.newFixedThreadPool(10);
HttpClient client = HttpClient.newBuilder()
    .executor(executor)
    .build();
# a、代理设置详解

使用代理是企业开发中的常见需求,Java 11 HttpClient提供了完善的代理支持:

// 基本代理配置
String proxyHost = "proxy.example.com";
int proxyPort = 8080;
String proxyUsername = "user";
String proxyPassword = "pass";

// 自定义ProxySelector
ProxySelector proxySelector = new ProxySelector() {
    @Override
    public List<Proxy> select(URI uri) {
        // 可以根据不同的URI返回不同的代理
        if (uri.getHost().contains("internal")) {
            return Collections.singletonList(Proxy.NO_PROXY);
        }
        InetSocketAddress proxyAddress = new InetSocketAddress(proxyHost, proxyPort);
        return Collections.singletonList(new Proxy(Proxy.Type.HTTP, proxyAddress));
    }

    @Override
    public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
        System.err.println("代理连接失败: " + uri);
    }
};

// 配置认证
HttpClient httpClient = HttpClient.newBuilder()
    .proxy(proxySelector)
    .authenticator(new Authenticator() {
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(proxyUsername, proxyPassword.toCharArray());
        }
    })
    .build();

重要提示:如果遇到代理认证失败(407错误),可能需要配置JVM系统属性:

// 启用Basic认证(默认被禁用)
System.setProperty("jdk.http.auth.proxying.disabledSchemes", "");
System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");

这是因为从Java 8u111开始,出于安全考虑,JDK默认禁用了Basic认证。这些配置可以在$JAVA_HOME/conf/net.properties中找到。

# 2.4、声明式HTTP客户端

声明式HTTP客户端让我们可以像调用本地方法一样调用远程API,大大简化了开发:

// 定义接口
public interface UserService {
    @Request(
        url = "https://api.example.com/users/{id}",
        headers = "Accept: application/json"
    )
    User getUser(@Path("id") Long userId);
    
    @PostRequest(url = "https://api.example.com/users")
    User createUser(@Body User user);
}

// 使用接口
UserService userService = Forest.client(UserService.class);
User user = userService.getUser(123L);  // 像调用本地方法一样简单

主流的声明式HTTP客户端框架:

  • Spring RestClient/WebClient:Spring生态原生支持,与Spring Boot集成最好
  • OpenFeign:Spring Cloud组件,微服务开发首选
  • Forest:国产框架,功能丰富,文档友好
  • Retrofit:Square出品,Android开发广泛使用

选择建议:

  • Spring Boot项目:优先使用Spring原生方案或OpenFeign
  • 非Spring项目:Forest或Retrofit都是不错的选择

# 四、总结

本文系统介绍了Java网络编程的核心技术,从底层的Socket编程到上层的HTTP编程,涵盖了BIO、NIO、AIO等不同的IO模型。

关键要点回顾:

  1. IO模型演进:BIO → NIO → AIO,每种模型都有其适用场景
  2. 框架选择:实际项目中优先使用成熟框架(Netty、Spring Boot)而非原生API
  3. 性能优化:理解不同并发模型的原理,根据业务特点选择合适的方案
  4. HTTP客户端:Java 11的HttpClient是现代化的选择,声明式客户端能提升开发效率

网络编程是个庞大的领域,本文只是介绍了最核心的部分。如果你想深入学习,建议:

  • 实践Netty开发,理解高性能网络编程
  • 研究Spring WebFlux,掌握响应式编程
  • 了解gRPC、WebSocket等其他协议

希望这篇文章能帮助你建立Java网络编程的知识体系。如有疑问或补充,欢迎交流讨论!

编辑 (opens new window)
#Java网络编程
上次更新: 2025/08/15
Java 文件操作
Java运行期动态能力

← Java 文件操作 Java运行期动态能力→

最近更新
01
AI时代的编程心得
09-11
02
Claude Code与Codex的协同工作
09-01
03
Claude Code实战之供应商切换工具
08-18
更多文章>
Theme by Vdoing | Copyright © 2018-2025 京ICP备2021021832号-2 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式