REST 与 RPC 深度解析:从理论到实践的全面对比

47 阅读12分钟

REST 与 RPC 深度解析:从理论到实践的全面对比

REST 和 RPC 是分布式系统中两种最重要的通信范式,它们代表了不同的设计哲学和适用场景。本文将深入探讨两者的区别,并通过丰富的代码示例帮助你做出正确的技术选型。

一、基础概念:什么是 REST 和 RPC?

1.1 REST(表述性状态转移)

REST 是一种架构风格,而不是标准或协议。它基于 HTTP 协议,强调资源的表述和状态转移。

// RESTful API 设计示例
@RestController
@RequestMapping("/api/users")
public class UserRestController {
    
    // GET /api/users/123 - 获取用户
    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        User user = userService.findById(id);
        return ResponseEntity.ok(user);
    }
    
    // POST /api/users - 创建用户
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        User created = userService.create(user);
        return ResponseEntity.status(HttpStatus.CREATED).body(created);
    }
    
    // PUT /api/users/123 - 更新用户
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User user) {
        user.setId(id);
        User updated = userService.update(user);
        return ResponseEntity.ok(updated);
    }
    
    // DELETE /api/users/123 - 删除用户
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.delete(id);
        return ResponseEntity.noContent().build();
    }
    
    // GET /api/users/123/orders - 获取用户的订单
    @GetMapping("/{id}/orders")
    public ResponseEntity<List<Order>> getUserOrders(@PathVariable Long id) {
        List<Order> orders = orderService.findByUserId(id);
        return ResponseEntity.ok(orders);
    }
}

1.2 RPC(远程过程调用)

RPC 是一种协议,允许程序调用另一个地址空间(通常是另一台机器)的过程或函数,就像调用本地方法一样。

// RPC 服务定义示例
public interface UserService {
    // 方法调用风格,不关心 HTTP 方法
    User getUserById(Long id);
    User createUser(User user);
    User updateUser(User user);
    void deleteUser(Long id);
    List<Order> getUserOrders(Long userId);
}

// gRPC 服务定义
service UserService {
    rpc GetUser (GetUserRequest) returns (UserResponse);
    rpc CreateUser (CreateUserRequest) returns (UserResponse);
    rpc UpdateUser (UpdateUserRequest) returns (UserResponse);
    rpc DeleteUser (DeleteUserRequest) returns (google.protobuf.Empty);
    rpc GetUserOrders (GetUserOrdersRequest) returns (GetUserOrdersResponse);
}

// Dubbo 服务实现
@Service
public class UserServiceImpl implements UserService {
    
    @Override
    public User getUserById(Long id) {
        return userMapper.selectById(id);
    }
    
    @Override
    public User createUser(User user) {
        userMapper.insert(user);
        return user;
    }
    
    @Override
    public List<Order> getUserOrders(Long userId) {
        return orderMapper.selectByUserId(userId);
    }
}

二、核心设计哲学对比

2.1 REST 的设计原则

// REST 的六个约束原则体现

// 1. 客户端-服务器架构
@RestController  // 明确的服务器角色
public class UserController {
    // 客户端通过 HTTP 调用
}

// 2. 无状态
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id, 
                   @RequestHeader("Authorization") String auth) {
    // 每次请求必须包含所有必要信息
    // 服务器不保存客户端状态
}

// 3. 可缓存
@GetMapping("/users/{id}")
@Cacheable(value = "users", key = "#id")  // 响应可被缓存
public User getUser(@PathVariable Long id) {
    // ...
}

// 4. 统一接口
public interface RestController {
    // 使用标准的 HTTP 方法
    // 资源标识符 (URI)
    // 自描述消息
}

// 5. 分层系统
// 客户端 -> 负载均衡器 -> 认证网关 -> 业务服务 -> 数据库

// 6. 按需代码(可选)
@GetMapping(value = "/users/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public User getUser(@PathVariable Long id) {
    // 返回 JSON 表述
}

2.2 RPC 的设计哲学

// RPC 的核心思想:像调用本地方法一样调用远程服务

// 服务接口定义
public interface CalculatorService {
    // 透明性:调用者不需要知道这是远程调用
    double add(double a, double b);
    double subtract(double a, double b);
    double multiply(double a, double b);
    double divide(double a, double b);
}

// 服务实现
@Service
public class CalculatorServiceImpl implements CalculatorService {
    
    @Override
    public double add(double a, double b) {
        return a + b;
    }
    
    @Override
    public double divide(double a, double b) {
        if (b == 0) {
            // 异常处理也是透明的
            throw new IllegalArgumentException("除数不能为零");
        }
        return a / b;
    }
}

// 客户端调用
@Component
public class CalculatorClient {
    
    @Reference  // Dubbo 的远程引用
    private CalculatorService calculatorService;
    
    public void calculate() {
        // 看起来像本地调用,实际上是远程调用
        double result = calculatorService.add(10.5, 20.3);
        System.out.println("计算结果: " + result);
        
        try {
            calculatorService.divide(10, 0);
        } catch (IllegalArgumentException e) {
            // 异常也是透明的
            System.out.println("捕获异常: " + e.getMessage());
        }
    }
}

三、技术实现对比

3.1 REST 实现详解

3.1.1 Spring Boot RESTful API
// 完整的 RESTful 服务实现
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long id;
    private String username;
    private String email;
    private String phone;
    private LocalDateTime createTime;
    private UserStatus status;
}

enum UserStatus {
    ACTIVE, INACTIVE, SUSPENDED
}

@RestController
@RequestMapping("/api/v1/users")
@Validated
@Slf4j
public class UserRestController {
    
    @Autowired
    private UserService userService;
    
    // 查询用户列表(支持分页、过滤、排序)
    @GetMapping
    public ResponseEntity<PageResponse<User>> getUsers(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size,
            @RequestParam(required = false) String username,
            @RequestParam(required = false) UserStatus status,
            @RequestParam(defaultValue = "id,desc") String sort) {
        
        log.info("查询用户列表 - page: {}, size: {}, username: {}, status: {}", 
                 page, size, username, status);
        
        PageRequest pageRequest = PageRequest.of(page, size, parseSort(sort));
        Page<User> users = userService.findUsers(username, status, pageRequest);
        
        PageResponse<User> response = PageResponse.of(users);
        return ResponseEntity.ok(response);
    }
    
    // 获取单个用户
    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        log.info("获取用户 - ID: {}", id);
        
        User user = userService.findById(id)
            .orElseThrow(() -> new ResourceNotFoundException("用户不存在"));
        
        return ResponseEntity.ok(user);
    }
    
    // 创建用户
    @PostMapping
    public ResponseEntity<User> createUser(@Valid @RequestBody CreateUserRequest request) {
        log.info("创建用户 - username: {}", request.getUsername());
        
        User user = userService.create(request);
        URI location = ServletUriComponentsBuilder
            .fromCurrentRequest()
            .path("/{id}")
            .buildAndExpand(user.getId())
            .toUri();
        
        return ResponseEntity.created(location).body(user);
    }
    
    // 部分更新用户
    @PatchMapping("/{id}")
    public ResponseEntity<User> partialUpdateUser(
            @PathVariable Long id, 
            @RequestBody Map<String, Object> updates) {
        log.info("部分更新用户 - ID: {}, updates: {}", id, updates);
        
        User user = userService.partialUpdate(id, updates);
        return ResponseEntity.ok(user);
    }
    
    // 获取用户的订单(子资源)
    @GetMapping("/{id}/orders")
    public ResponseEntity<List<Order>> getUserOrders(@PathVariable Long id) {
        log.info("获取用户订单 - 用户ID: {}", id);
        
        List<Order> orders = orderService.findByUserId(id);
        return ResponseEntity.ok(orders);
    }
    
    // 启用用户(特定操作)
    @PostMapping("/{id}/enable")
    public ResponseEntity<Void> enableUser(@PathVariable Long id) {
        log.info("启用用户 - ID: {}", id);
        
        userService.enableUser(id);
        return ResponseEntity.ok().build();
    }
    
    // 自定义排序解析
    private Sort parseSort(String sort) {
        String[] parts = sort.split(",");
        if (parts.length != 2) {
            return Sort.by("id").descending();
        }
        
        String property = parts[0];
        Sort.Direction direction = "desc".equalsIgnoreCase(parts[1]) 
            ? Sort.Direction.DESC 
            : Sort.Direction.ASC;
            
        return Sort.by(direction, property);
    }
}

// 分页响应包装类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageResponse<T> {
    private List<T> content;
    private int page;
    private int size;
    private long totalElements;
    private int totalPages;
    
    public static <T> PageResponse<T> of(Page<T> page) {
        return new PageResponse<>(
            page.getContent(),
            page.getNumber(),
            page.getSize(),
            page.getTotalElements(),
            page.getTotalPages()
        );
    }
}
3.1.2 REST 客户端实现
// 使用 RestTemplate 的 REST 客户端
@Component
@Slf4j
public class UserRestClient {
    
    private final RestTemplate restTemplate;
    private final String baseUrl;
    
    public UserRestClient(@Value("${user.service.url}") String baseUrl) {
        this.baseUrl = baseUrl;
        this.restTemplate = new RestTemplate();
        
        // 配置 RestTemplate
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
            @Override
            public void handleError(ClientHttpResponse response) throws IOException {
                if (response.getStatusCode() == HttpStatus.NOT_FOUND) {
                    throw new ResourceNotFoundException("用户不存在");
                }
                super.handleError(response);
            }
        });
    }
    
    public User getUserById(Long id) {
        String url = baseUrl + "/api/v1/users/" + id;
        
        try {
            ResponseEntity<User> response = restTemplate.getForEntity(url, User.class);
            return response.getBody();
        } catch (ResourceNotFoundException e) {
            log.warn("用户不存在 - ID: {}", id);
            return null;
        }
    }
    
    public User createUser(User user) {
        String url = baseUrl + "/api/v1/users";
        
        ResponseEntity<User> response = restTemplate.postForEntity(url, user, User.class);
        return response.getBody();
    }
    
    public void updateUser(Long id, User user) {
        String url = baseUrl + "/api/v1/users/" + id;
        restTemplate.put(url, user);
    }
    
    public void deleteUser(Long id) {
        String url = baseUrl + "/api/v1/users/" + id;
        restTemplate.delete(url);
    }
    
    // 带查询参数的调用
    public List<User> findUsers(String username, UserStatus status) {
        String url = baseUrl + "/api/v1/users";
        
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
        if (username != null) {
            builder.queryParam("username", username);
        }
        if (status != null) {
            builder.queryParam("status", status);
        }
        
        ResponseEntity<User[]> response = restTemplate.getForEntity(
            builder.toUriString(), User[].class);
        
        return Arrays.asList(response.getBody());
    }
}

// 使用 OpenFeign 的声明式 REST 客户端
@FeignClient(name = "user-service", url = "${user.service.url}")
public interface UserServiceClient {
    
    @GetMapping("/api/v1/users/{id}")
    ResponseEntity<User> getUserById(@PathVariable("id") Long id);
    
    @PostMapping("/api/v1/users")
    ResponseEntity<User> createUser(@RequestBody User user);
    
    @PutMapping("/api/v1/users/{id}")
    ResponseEntity<Void> updateUser(@PathVariable("id") Long id, @RequestBody User user);
    
    @DeleteMapping("/api/v1/users/{id}")
    ResponseEntity<Void> deleteUser(@PathVariable("id") Long id);
    
    @GetMapping("/api/v1/users")
    ResponseEntity<List<User>> findUsers(
        @RequestParam(value = "username", required = false) String username,
        @RequestParam(value = "status", required = false) UserStatus status);
}

3.2 RPC 实现详解

3.2.1 gRPC 实现

proto 文件定义:

syntax = "proto3";

package com.example.grpc;

import "google/protobuf/timestamp.proto";
import "google/protobuf/empty.proto";

service UserService {
  rpc GetUser (GetUserRequest) returns (UserResponse);
  rpc CreateUser (CreateUserRequest) returns (UserResponse);
  rpc UpdateUser (UpdateUserRequest) returns (UserResponse);
  rpc DeleteUser (DeleteUserRequest) returns (google.protobuf.Empty);
  rpc ListUsers (ListUsersRequest) returns (ListUsersResponse);
  rpc BatchGetUsers (BatchGetUsersRequest) returns (BatchGetUsersResponse);
}

message GetUserRequest {
  int64 id = 1;
}

message CreateUserRequest {
  string username = 1;
  string email = 2;
  string phone = 3;
}

message UpdateUserRequest {
  int64 id = 1;
  string username = 2;
  string email = 3;
  string phone = 4;
}

message DeleteUserRequest {
  int64 id = 1;
}

message ListUsersRequest {
  int32 page = 1;
  int32 size = 2;
  string username_filter = 3;
  UserStatus status_filter = 4;
}

message BatchGetUsersRequest {
  repeated int64 ids = 1;
}

message UserResponse {
  int64 id = 1;
  string username = 2;
  string email = 3;
  string phone = 4;
  google.protobuf.Timestamp create_time = 5;
  UserStatus status = 6;
}

message ListUsersResponse {
  repeated UserResponse users = 1;
  int32 total_pages = 2;
  int64 total_elements = 3;
}

message BatchGetUsersResponse {
  repeated UserResponse users = 1;
}

enum UserStatus {
  ACTIVE = 0;
  INACTIVE = 1;
  SUSPENDED = 2;
}

gRPC 服务端实现:

// gRPC 服务实现
@Service
@Slf4j
public class UserGrpcService extends UserServiceGrpc.UserServiceImplBase {
    
    @Autowired
    private UserService userService;
    
    @Override
    public void getUser(GetUserRequest request, StreamObserver<UserResponse> responseObserver) {
        log.info("gRPC - 获取用户: {}", request.getId());
        
        try {
            User user = userService.findById(request.getId())
                .orElseThrow(() -> Status.NOT_FOUND
                    .withDescription("用户不存在")
                    .asRuntimeException());
                    
            UserResponse response = buildUserResponse(user);
            responseObserver.onNext(response);
            responseObserver.onCompleted();
            
        } catch (Exception e) {
            responseObserver.onError(e);
        }
    }
    
    @Override
    public void createUser(CreateUserRequest request, StreamObserver<UserResponse> responseObserver) {
        log.info("gRPC - 创建用户: {}", request.getUsername());
        
        try {
            User user = new User();
            user.setUsername(request.getUsername());
            user.setEmail(request.getEmail());
            user.setPhone(request.getPhone());
            
            User created = userService.create(user);
            UserResponse response = buildUserResponse(created);
            
            responseObserver.onNext(response);
            responseObserver.onCompleted();
            
        } catch (Exception e) {
            responseObserver.onError(Status.INTERNAL
                .withDescription("创建用户失败")
                .withCause(e)
                .asRuntimeException());
        }
    }
    
    @Override
    public void listUsers(ListUsersRequest request, StreamObserver<ListUsersResponse> responseObserver) {
        log.info("gRPC - 查询用户列表");
        
        try {
            PageRequest pageRequest = PageRequest.of(
                request.getPage(), 
                request.getSize()
            );
            
            Page<User> users = userService.findUsers(
                request.getUsernameFilter(),
                convertStatus(request.getStatusFilter()),
                pageRequest
            );
            
            ListUsersResponse response = buildListUsersResponse(users);
            responseObserver.onNext(response);
            responseObserver.onCompleted();
            
        } catch (Exception e) {
            responseObserver.onError(e);
        }
    }
    
    @Override
    public void batchGetUsers(BatchGetUsersRequest request, StreamObserver<BatchGetUsersResponse> responseObserver) {
        log.info("gRPC - 批量获取用户: {}", request.getIdsList());
        
        try {
            List<User> users = userService.findByIds(request.getIdsList());
            
            BatchGetUsersResponse response = BatchGetUsersResponse.newBuilder()
                .addAllUsers(users.stream()
                    .map(this::buildUserResponse)
                    .collect(Collectors.toList()))
                .build();
                
            responseObserver.onNext(response);
            responseObserver.onCompleted();
            
        } catch (Exception e) {
            responseObserver.onError(e);
        }
    }
    
    private UserResponse buildUserResponse(User user) {
        return UserResponse.newBuilder()
            .setId(user.getId())
            .setUsername(user.getUsername())
            .setEmail(user.getEmail())
            .setPhone(user.getPhone())
            .setCreateTime(Timestamp.newBuilder()
                .setSeconds(user.getCreateTime().toEpochSecond(ZoneOffset.UTC))
                .build())
            .setStatus(convertStatus(user.getStatus()))
            .build();
    }
    
    private ListUsersResponse buildListUsersResponse(Page<User> users) {
        return ListUsersResponse.newBuilder()
            .addAllUsers(users.getContent().stream()
                .map(this::buildUserResponse)
                .collect(Collectors.toList()))
            .setTotalPages(users.getTotalPages())
            .setTotalElements(users.getTotalElements())
            .build();
    }
    
    private com.example.grpc.UserStatus convertStatus(UserStatus status) {
        switch (status) {
            case ACTIVE: return com.example.grpc.UserStatus.ACTIVE;
            case INACTIVE: return com.example.grpc.UserStatus.INACTIVE;
            case SUSPENDED: return com.example.grpc.UserStatus.SUSPENDED;
            default: return com.example.grpc.UserStatus.ACTIVE;
        }
    }
    
    private UserStatus convertStatus(com.example.grpc.UserStatus status) {
        switch (status) {
            case ACTIVE: return UserStatus.ACTIVE;
            case INACTIVE: return UserStatus.INACTIVE;
            case SUSPENDED: return UserStatus.SUSPENDED;
            default: return UserStatus.ACTIVE;
        }
    }
}

gRPC 客户端实现:

// gRPC 客户端
@Component
@Slf4j
public class UserGrpcClient {
    
    private final UserServiceGrpc.UserServiceBlockingStub blockingStub;
    private final UserServiceGrpc.UserServiceStub asyncStub;
    
    public UserGrpcClient(@Value("${grpc.user-service.host:localhost}") String host,
                         @Value("${grpc.user-service.port:9090}") int port) {
        ManagedChannel channel = ManagedChannelBuilder.forAddress(host, port)
            .usePlaintext()  // 生产环境使用 TLS
            .build();
            
        this.blockingStub = UserServiceGrpc.newBlockingStub(channel);
        this.asyncStub = UserServiceGrpc.newStub(channel);
    }
    
    public User getUser(Long id) {
        log.info("gRPC客户端 - 获取用户: {}", id);
        
        try {
            GetUserRequest request = GetUserRequest.newBuilder()
                .setId(id)
                .build();
                
            UserResponse response = blockingStub.getUser(request);
            return convertToUser(response);
            
        } catch (StatusRuntimeException e) {
            if (e.getStatus().getCode() == Status.Code.NOT_FOUND) {
                log.warn("用户不存在: {}", id);
                return null;
            }
            log.error("gRPC调用失败: {}", e.getStatus());
            throw new RuntimeException("用户服务调用失败", e);
        }
    }
    
    public User createUser(User user) {
        log.info("gRPC客户端 - 创建用户: {}", user.getUsername());
        
        CreateUserRequest request = CreateUserRequest.newBuilder()
            .setUsername(user.getUsername())
            .setEmail(user.getEmail())
            .setPhone(user.getPhone())
            .build();
            
        UserResponse response = blockingStub.createUser(request);
        return convertToUser(response);
    }
    
    public List<User> listUsers(int page, int size, String usernameFilter) {
        log.info("gRPC客户端 - 查询用户列表");
        
        ListUsersRequest request = ListUsersRequest.newBuilder()
            .setPage(page)
            .setSize(size)
            .setUsernameFilter(usernameFilter != null ? usernameFilter : "")
            .build();
            
        ListUsersResponse response = blockingStub.listUsers(request);
        
        return response.getUsersList().stream()
            .map(this::convertToUser)
            .collect(Collectors.toList());
    }
    
    // 异步调用
    public CompletableFuture<List<User>> batchGetUsersAsync(List<Long> ids) {
        log.info("gRPC客户端 - 异步批量获取用户: {}", ids);
        
        CompletableFuture<List<User>> future = new CompletableFuture<>();
        
        BatchGetUsersRequest request = BatchGetUsersRequest.newBuilder()
            .addAllIds(ids)
            .build();
            
        asyncStub.batchGetUsers(request, new StreamObserver<BatchGetUsersResponse>() {
            private final List<User> users = new ArrayList<>();
            
            @Override
            public void onNext(BatchGetUsersResponse response) {
                users.addAll(response.getUsersList().stream()
                    .map(UserGrpcClient.this::convertToUser)
                    .collect(Collectors.toList()));
            }
            
            @Override
            public void onError(Throwable t) {
                log.error("异步批量获取用户失败", t);
                future.completeExceptionally(t);
            }
            
            @Override
            public void onCompleted() {
                future.complete(users);
            }
        });
        
        return future;
    }
    
    private User convertToUser(UserResponse response) {
        User user = new User();
        user.setId(response.getId());
        user.setUsername(response.getUsername());
        user.setEmail(response.getEmail());
        user.setPhone(response.getPhone());
        user.setCreateTime(LocalDateTime.ofInstant(
            Instant.ofEpochSecond(response.getCreateTime().getSeconds()),
            ZoneOffset.UTC
        ));
        user.setStatus(convertFromGrpcStatus(response.getStatus()));
        return user;
    }
    
    private UserStatus convertFromGrpcStatus(com.example.grpc.UserStatus status) {
        switch (status) {
            case ACTIVE: return UserStatus.ACTIVE;
            case INACTIVE: return UserStatus.INACTIVE;
            case SUSPENDED: return UserStatus.SUSPENDED;
            default: return UserStatus.ACTIVE;
        }
    }
}
3.2.2 Dubbo RPC 实现
// Dubbo 服务接口
public interface UserRpcService {
    User getUserById(Long id);
    User createUser(User user);
    User updateUser(User user);
    void deleteUser(Long id);
    PageResult<User> listUsers(int page, int size, String username, UserStatus status);
    List<User> batchGetUsers(List<Long> ids);
}

// Dubbo 服务实现
@Service
@Slf4j
public class UserRpcServiceImpl implements UserRpcService {
    
    @Autowired
    private UserService userService;
    
    @Override
    public User getUserById(Long id) {
        log.info("Dubbo - 获取用户: {}", id);
        return userService.findById(id)
            .orElseThrow(() -> new RuntimeException("用户不存在"));
    }
    
    @Override
    public User createUser(User user) {
        log.info("Dubbo - 创建用户: {}", user.getUsername());
        return userService.create(user);
    }
    
    @Override
    public PageResult<User> listUsers(int page, int size, String username, UserStatus status) {
        log.info("Dubbo - 查询用户列表");
        
        PageRequest pageRequest = PageRequest.of(page, size);
        Page<User> users = userService.findUsers(username, status, pageRequest);
        
        return PageResult.of(users.getContent(), 
                           users.getTotalElements(), 
                           users.getTotalPages());
    }
    
    @Override
    public List<User> batchGetUsers(List<Long> ids) {
        log.info("Dubbo - 批量获取用户: {}", ids);
        return userService.findByIds(ids);
    }
}

// Dubbo 配置
@Configuration
public class DubboConfig {
    
    @Bean
    public ApplicationConfig applicationConfig() {
        ApplicationConfig config = new ApplicationConfig();
        config.setName("user-service");
        return config;
    }
    
    @Bean
    public RegistryConfig registryConfig() {
        RegistryConfig config = new RegistryConfig();
        config.setAddress("nacos://localhost:8848");
        return config;
    }
    
    @Bean
    public ProtocolConfig protocolConfig() {
        ProtocolConfig config = new ProtocolConfig();
        config.setName("dubbo");
        config.setPort(20880);
        return config;
    }
    
    @Bean
    public ServiceConfig<UserRpcService> userServiceConfig(UserRpcService userService) {
        ServiceConfig<UserRpcService> service = new ServiceConfig<>();
        service.setInterface(UserRpcService.class);
        service.setRef(userService);
        service.setVersion("1.0.0");
        return service;
    }
}

// Dubbo 客户端使用
@Component
@Slf4j
public class UserRpcClient {
    
    @Reference(version = "1.0.0", check = false)
    private UserRpcService userRpcService;
    
    public void demonstrateRpcCalls() {
        // 1. 获取单个用户
        try {
            User user = userRpcService.getUserById(1L);
            log.info("获取用户成功: {}", user.getUsername());
        } catch (Exception e) {
            log.error("获取用户失败", e);
        }
        
        // 2. 创建用户
        User newUser = new User();
        newUser.setUsername("newuser");
        newUser.setEmail("newuser@example.com");
        
        User created = userRpcService.createUser(newUser);
        log.info("创建用户成功, ID: {}", created.getId());
        
        // 3. 批量查询
        List<User> users = userRpcService.listUsers(0, 10, null, null).getData();
        log.info("查询到 {} 个用户", users.size());
        
        // 4. 批量获取
        List<User> batchUsers = userRpcService.batchGetUsers(Arrays.asList(1L, 2L, 3L));
        log.info("批量获取到 {} 个用户", batchUsers.size());
    }
}

四、通信流程对比

4.1 REST 通信流程图

sequenceDiagram
    participant C as REST Client
    participant S as REST Server
    
    Note over C,S: 1. 获取用户 (GET)
    C->>S: GET /api/users/123
    Note right of S: 解析URL路径参数<br>查询数据库
    S-->>C: 200 OK + User JSON
    
    Note over C,S: 2. 创建用户 (POST)
    C->>S: POST /api/users
    Note right of S: 验证请求体<br>创建用户记录
    S-->>C: 201 Created + User JSON
    
    Note over C,S: 3. 更新用户 (PUT)
    C->>S: PUT /api/users/123
    Note right of S: 全量更新用户信息
    S-->>C: 200 OK + User JSON
    
    Note over C,S: 4. 删除用户 (DELETE)
    C->>S: DELETE /api/users/123
    Note right of S: 删除用户记录
    S-->>C: 204 No Content
    
    Note over C,S: 5. 获取用户订单 (子资源)
    C->>S: GET /api/users/123/orders
    Note right of S: 查询关联订单
    S-->>C: 200 OK + Orders JSON

4.2 RPC 通信流程图

sequenceDiagram
    participant C as RPC Client
    participant P as Proxy/Stub
    participant N as Network
    participant S as RPC Server
    
    Note over C,S: 1. 方法调用透明化
    C->>P: userService.getUser(123)
    
    Note over P: 序列化参数<br>创建请求消息
    P->>N: 发送二进制数据
    
    Note over N: 网络传输 (TCP/HTTP2)
    N->>S: 接收请求
    
    Note over S: 反序列化<br>查找服务方法
    S->>S: 执行业务逻辑
    
    S->>N: 返回二进制响应
    N->>P: 接收响应
    
    Note over P: 反序列化结果<br>处理异常
    P-->>C: 返回User对象或抛出异常
    
    Note over C,S: 2. 批量调用示例
    C->>P: userService.batchGetUsers([1,2,3])
    P->>N: 批量请求
    N->>S: 传输批量请求
    S->>S: 批量处理逻辑
    S->>N: 批量响应
    N->>P: 接收批量结果
    P-->>C: 返回List<User>

五、性能与特性对比

5.1 性能基准测试

// 性能测试对比
@SpringBootTest
@Slf4j
public class RestVsRpcPerformanceTest {
    
    @Autowired
    private UserRestClient restClient;
    
    @Autowired
    private UserGrpcClient grpcClient;
    
    @Autowired
    private UserRpcClient dubboClient;
    
    private static final int WARMUP_ITERATIONS = 100;
    private static final int TEST_ITERATIONS = 1000;
    
    @Test
    public void testSingleUserQuery() {
        // 预热
        warmup();
        
        // REST 测试
        long restTime = measureRestPerformance();
        
        // gRPC 测试
        long grpcTime = measureGrpcPerformance();
        
        // Dubbo 测试
        long dubboTime = measureDubboPerformance();
        
        log.info("=== 单用户查询性能测试结果 ===");
        log.info("REST 平均耗时: {} ms", restTime);
        log.info("gRPC 平均耗时: {} ms", grpcTime);
        log.info("Dubbo 平均耗时: {} ms", dubboTime);
        log.info("gRPC 比 REST 快: {}%", (restTime - grpcTime) * 100 / restTime);
    }
    
    @Test
    public void testBatchUsersQuery() {
        List<Long> ids = Arrays.asList(1L, 2L, 3L, 4L, 5L);
        
        long restTime = measureRestBatchPerformance(ids);
        long grpcTime = measureGrpcBatchPerformance(ids);
        long dubboTime = measureDubboBatchPerformance(ids);
        
        log.info("=== 批量用户查询性能测试结果 ===");
        log.info("REST 批量平均耗时: {} ms", restTime);
        log.info("gRPC 批量平均耗时: {} ms", grpcTime);
        log.info("Dubbo 批量平均耗时: {} ms", dubboTime);
    }
    
    private void warmup() {
        for (int i = 0; i < WARMUP_ITERATIONS; i++) {
            restClient.getUserById(1L);
            grpcClient.getUser(1L);
            dubboClient.getUserById(1L);
        }
    }
    
    private long measureRestPerformance() {
        long startTime = System.currentTimeMillis();
        
        for (int i = 0; i < TEST_ITERATIONS; i++) {
            restClient.getUserById((long) (i % 100 + 1));
        }
        
        return (System.currentTimeMillis() - startTime) / TEST_ITERATIONS;
    }
    
    private long measureGrpcPerformance() {
        long startTime = System.currentTimeMillis();
        
        for (int i = 0; i < TEST_ITERATIONS; i++) {
            grpcClient.getUser((long) (i % 100 + 1));
        }
        
        return (System.currentTimeMillis() - startTime) / TEST_ITERATIONS;
    }
    
    // 其他测试方法...
}

5.2 特性对比表格

特性RESTgRPCDubbo
通信协议HTTP/1.1HTTP/2多协议支持
数据格式JSON/XMLProtocol Buffers多种序列化
性能中等
浏览器支持有限有限
代码生成可选强制的可选
流式支持有限有限
服务发现需要额外组件需要额外组件内置
负载均衡客户端/服务端客户端客户端
容错机制需要额外实现需要额外实现内置

六、适用场景分析

6.1 REST 适用场景

// 场景1: 面向外部API
@RestController
@RequestMapping("/public/api/v1")
@Api(tags = "用户管理API")
public class PublicUserController {
    
    @GetMapping("/users/{id}")
    @ApiOperation("获取用户信息")
    public ResponseEntity<UserResponse> getPublicUser(@PathVariable Long id) {
        // 对外API,需要丰富的文档和标准化的错误处理
    }
    
    @PostMapping("/users")
    @ApiOperation("创建用户")
    public ResponseEntity<UserResponse> createPublicUser(
            @Valid @RequestBody CreateUserRequest request) {
        // 输入验证、API版本管理
    }
}

// 场景2: 资源型操作
@RestController
@RequestMapping("/api/documents")
public class DocumentController {
    
    @PostMapping("/{id}/publish")
    public ResponseEntity<Void> publishDocument(@PathVariable Long id) {
        // 发布文档 - 特定操作
    }
    
    @PostMapping("/{id}/versions")
    public ResponseEntity<DocumentVersion> createVersion(
            @PathVariable Long id, 
            @RequestBody CreateVersionRequest request) {
        // 创建新版本 - 子资源操作
    }
    
    @GetMapping("/{id}/permissions")
    public ResponseEntity<DocumentPermissions> getPermissions(@PathVariable Long id) {
        // 获取权限 - 子资源查询
    }
}

6.2 RPC 适用场景

// 场景1: 高性能内部服务调用
public interface OrderProcessingService {
    // 内部服务,需要高性能
    ProcessingResult processOrder(Order order);
    
    // 批量处理
    List<ProcessingResult> batchProcessOrders(List<Order> orders);
    
    // 流式处理
    StreamObserver<Order> streamProcessOrders(StreamObserver<ProcessingResult> responseObserver);
}

// 场景2: 复杂计算服务
public interface RiskCalculationService {
    // 复杂的计算逻辑,不需要资源概念
    RiskAssessment calculateRisk(RiskFactors factors);
    
    // 实时风险监控
    StreamObserver<MarketData> monitorRisk(StreamObserver<RiskAlert> responseObserver);
}

// 场景3: 实时通信
public interface ChatService {
    // 双向流式通信
    StreamObserver<ChatMessage> chat(StreamObserver<ChatMessage> responseObserver);
    
    // 实时通知
    void notifyUser(Long userId, Notification notification);
}

七、混合使用策略

7.1 API 网关模式

// API 网关 - 对外REST,对内RPC
@RestController
@RequestMapping("/api/v1")
@Slf4j
public class ApiGatewayController {
    
    @Autowired
    private UserRpcService userRpcService;
    
    @Autowired
    private OrderRpcService orderRpcService;
    
    // 对外提供 RESTful API
    @GetMapping("/users/{id}")
    public ResponseEntity<UserResponse> getUser(@PathVariable Long id) {
        try {
            // 内部使用 RPC 调用
            User user = userRpcService.getUserById(id);
            UserResponse response = convertToResponse(user);
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            log.error("获取用户失败", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }
    
    @GetMapping("/users/{userId}/orders")
    public ResponseEntity<List<OrderResponse>> getUserOrders(
            @PathVariable Long userId,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size) {
        
        // 组合多个 RPC 调用
        User user = userRpcService.getUserById(userId);
        PageResult<Order> orders = orderRpcService.getUserOrders(userId, page, size);
        
        List<OrderResponse> responses = orders.getData().stream()
            .map(order -> convertToOrderResponse(order, user))
            .collect(Collectors.toList());
            
        return ResponseEntity.ok(responses);
    }
    
    // 数据转换
    private UserResponse convertToResponse(User user) {
        UserResponse response = new UserResponse();
        response.setId(user.getId());
        response.setUsername(user.getUsername());
        response.setEmail(user.getEmail());
        response.setCreateTime(user.getCreateTime());
        return response;
    }
    
    private OrderResponse convertToOrderResponse(Order order, User user) {
        OrderResponse response = new OrderResponse();
        response.setId(order.getId());
        response.setOrderNumber(order.getOrderNumber());
        response.setAmount(order.getAmount());
        response.setUserName(user.getUsername());
        return response;
    }
}

7.2 BFF (Backend For Frontend) 模式

// 移动端 BFF
@RestController
@RequestMapping("/mobile/api/v1")
@Slf4j
public class MobileBffController {
    
    @GetMapping("/user-dashboard")
    public ResponseEntity<UserDashboard> getUserDashboard(@RequestHeader("User-ID") Long userId) {
        // 为移动端定制的聚合接口
        User user = userRpcService.getUserById(userId);
        List<Order> recentOrders = orderRpcService.getRecentOrders(userId, 5);
        List<Notification> notifications = notificationRpcService.getUnreadNotifications(userId);
        
        UserDashboard dashboard = new UserDashboard();
        dashboard.setUser(user);
        dashboard.setRecentOrders(recentOrders);
        dashboard.setNotifications(notifications);
        
        return ResponseEntity.ok(dashboard);
    }
}

// Web 端 BFF  
@RestController
@RequestMapping("/web/api/v1")
@Slf4j
public class WebBffController {
    
    @GetMapping("/admin-dashboard")
    public ResponseEntity<AdminDashboard> getAdminDashboard() {
        // 为Web管理端定制的聚合接口
        long totalUsers = userRpcService.getUserCount();
        long totalOrders = orderRpcService.getOrderCount();
        SystemStats systemStats = systemRpcService.getSystemStats();
        
        AdminDashboard dashboard = new AdminDashboard();
        dashboard.setTotalUsers(totalUsers);
        dashboard.setTotalOrders(totalOrders);
        dashboard.setSystemStats(systemStats);
        
        return ResponseEntity.ok(dashboard);
    }
}

八、总结

8.1 核心区别总结

方面RESTRPC
设计哲学资源导向,状态转移方法导向,过程调用
通信范式基于HTTP方法的CRUD操作基于接口方法的远程调用
数据格式文本格式(JSON/XML)二进制格式(Protobuf/Thrift)
耦合程度松耦合(通过超媒体)紧耦合(需要接口定义)
可发现性自描述,易于探索需要接口文档
性能中等,文本解析开销高,二进制序列化
缓存支持天然支持HTTP缓存需要额外实现
浏览器支持完全支持有限支持

8.2 选择指南

选择 REST 当:

  • 面向外部API或第三方集成
  • 需要良好的可发现性和文档
  • 利用HTTP缓存机制
  • 系统需要松耦合
  • 浏览器客户端是主要消费者

选择 RPC 当:

  • 内部服务间高性能通信
  • 强类型和接口契约很重要
  • 需要双向流式通信
  • 系统已经采用微服务架构
  • 对性能有极致要求

8.3 现代最佳实践

  1. 混合架构: 对外REST + 对内RPC
  2. API网关: 统一入口,协议转换
  3. BFF模式: 为不同客户端定制API
  4. gRPC-Web: 在浏览器中使用gRPC
  5. 统一认证: 无论哪种协议,统一安全机制

通过理解REST和RPC的深层区别,你可以在不同的场景中做出恰当的技术选择,构建出既满足性能要求又具备良好可维护性的分布式系统。

进一步学习建议:

  • 深入学习 GraphQL 作为 REST 的替代方案
  • 了解 gRPC 的流式处理和拦截器
  • 掌握 API 版本管理策略
  • 学习微服务通信模式

Happy API Designing! 🚀