引子:一个订单创建背后的两个世界 2025年某天上午10点,你接到一个需求:开发一个电商订单创建功能。
需求很简单:
验证用户权限 查询商品信息 扣减库存 创建订单记录 调用支付服务 发送通知 如果用纯Java实现,需要多少代码?如果用Spring实现,又需要多少代码?
让我们来看看两个完全不同的世界。
一、场景A:纯Java实现(无框架的艰辛) 1.1 完整代码实现 /** * 订单服务 - 纯Java实现 * 问题:硬编码依赖、事务手动管理、横切关注点混杂 */ public class OrderService { // 依赖对象(硬编码new) private UserService userService; private ProductService productService; private InventoryService inventoryService; private PaymentService paymentService; private NotificationService notificationService; // 数据库连接(硬编码配置) private static final String DB_URL = "jdbc:mysql://localhost:3306/mydb"; private static final String DB_USER = "root"; private static final String DB_PASSWORD = "123456"; /** * 构造函数:手动创建所有依赖 * 问题1:依赖层级深,任何一个依赖变化都需要修改这里 */ public OrderService() { // 每个依赖都要手动new,且需要传入它们的依赖 this.userService = new UserService( new UserRepository(getDataSource()) ); this.productService = new ProductService( new ProductRepository(getDataSource()) ); this.inventoryService = new InventoryService( new InventoryRepository(getDataSource()), new RedisClient("localhost", 6379) ); // 支付服务硬编码为支付宝(无法切换) this.paymentService = new AlipayPaymentService( new AlipayConfig("app_id_xxx", "private_key_xxx") ); this.notificationService = new EmailNotificationService( new EmailConfig("smtp.qq.com", 587, "user@qq.com", "password") ); } /** * 创建订单 * 问题2:横切关注点混杂(事务、日志、权限散落在业务代码中) */ public Order createOrder(OrderRequest request) { // ========== 横切关注点1:日志记录 ========== System.out.println("========================================"); System.out.println("开始创建订单: " + request); System.out.println("时间: " + new Date()); long startTime = System.currentTimeMillis(); Connection conn = null; try { // ========== 横切关注点2:权限校验 ========== User user = userService.getUser(request.getUserId()); if (user == null) { throw new BusinessException("用户不存在"); } if (!user.hasPermission("CREATE_ORDER")) { System.err.println("权限拒绝: 用户 " + user.getId() + " 无CREATE_ORDER权限"); throw new PermissionException("无权限创建订单"); } // ========== 横切关注点3:参数校验 ========== if (request.getProductId() == null) { throw new ValidationException("商品ID不能为空"); } if (request.getQuantity() == null || request.getQuantity() <= 0) { throw new ValidationException("购买数量必须大于0"); } // ========== 横切关注点4:手动事务管理 ========== conn = getConnection(); conn.setAutoCommit(false); // 关闭自动提交 try { // ========== 核心业务逻辑开始(只占20%代码) ========== // 1. 查询商品 Product product = productService.getProduct(request.getProductId()); if (product == null) { throw new BusinessException("商品不存在"); } if (product.getStatus() != 1) { throw new BusinessException("商品已下架"); } // 2. 扣减库存 boolean deductSuccess = inventoryService.deduct( product.getId(), request.getQuantity(), conn // 传递同一个连接,保证事务一致性 ); if (!deductSuccess) { throw new BusinessException("库存不足"); } // 3. 创建订单 Order order = new Order(); order.setOrderNo(generateOrderNo()); order.setUserId(user.getId()); order.setProductId(product.getId()); order.setProductName(product.getName()); order.setQuantity(request.getQuantity()); order.setPrice(product.getPrice()); order.setAmount(product.getPrice().multiply( new BigDecimal(request.getQuantity()) )); order.setStatus(0); // 待支付 order.setCreateTime(new Date()); // 4. 保存订单到数据库 saveOrder(order, conn); // 5. 调用支付服务 boolean paymentSuccess = paymentService.pay( order.getOrderNo(), order.getAmount() ); if (!paymentSuccess) { throw new BusinessException("支付失败"); } // 6. 更新订单状态 order.setStatus(1); // 已支付 updateOrderStatus(order, conn); // ========== 核心业务逻辑结束 ========== // 提交事务 conn.commit(); // ========== 横切关注点5:发送通知(异步) ========== try { notificationService.sendEmail( user.getEmail(), "订单创建成功", "您的订单 " + order.getOrderNo() + " 已创建成功" ); } catch (Exception e) { // 通知失败不影响主流程 System.err.println("发送邮件失败: " + e.getMessage()); } // ========== 横切关注点6:日志记录 ========== long endTime = System.currentTimeMillis(); System.out.println("订单创建成功: " + order.getOrderNo()); System.out.println("耗时: " + (endTime - startTime) + "ms"); System.out.println("========================================"); return order; } catch (Exception e) { // 回滚事务 if (conn != null) { try { conn.rollback(); System.err.println("事务回滚成功"); } catch (SQLException rollbackEx) { System.err.println("事务回滚失败: " + rollbackEx.getMessage()); } } // ========== 横切关注点7:异常日志 ========== System.err.println("订单创建失败: " + e.getMessage()); e.printStackTrace(); throw new BusinessException("订单创建失败: " + e.getMessage(), e); } } catch (Exception e) { throw new RuntimeException("系统异常", e); } finally { // 释放连接 if (conn != null) { try { conn.close(); } catch (SQLException e) { System.err.println("关闭连接失败: " + e.getMessage()); } } } } /** * 获取数据库连接(硬编码配置) */ private Connection getConnection() throws SQLException { return DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD); } /** * 获取数据源 */ private DataSource getDataSource() { HikariDataSource ds = new HikariDataSource(); ds.setJdbcUrl(DB_URL); ds.setUsername(DB_USER); ds.setPassword(DB_PASSWORD); ds.setMaximumPoolSize(10); return ds; } /** * 生成订单号 */ private String generateOrderNo() { return "ORD" + System.currentTimeMillis() + (int)(Math.random() * 1000); } /** * 保存订单 */ private void saveOrder(Order order, Connection conn) throws SQLException { String sql = "INSERT INTO orders (order_no, user_id, product_id, " + "product_name, quantity, price, amount, status, create_time) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; try (PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setString(1, order.getOrderNo()); pstmt.setLong(2, order.getUserId()); pstmt.setLong(3, order.getProductId()); pstmt.setString(4, order.getProductName()); pstmt.setInt(5, order.getQuantity()); pstmt.setBigDecimal(6, order.getPrice()); pstmt.setBigDecimal(7, order.getAmount()); pstmt.setInt(8, order.getStatus()); pstmt.setTimestamp(9, new Timestamp(order.getCreateTime().getTime())); pstmt.executeUpdate(); } } /** * 更新订单状态 */ private void updateOrderStatus(Order order, Connection conn) throws SQLException { String sql = "UPDATE orders SET status = ? WHERE order_no = ?"; try (PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setInt(1, order.getStatus()); pstmt.setString(2, order.getOrderNo()); pstmt.executeUpdate(); } } } 1.2 代码统计与问题分析 代码统计:
...