Spring第一性原理:为什么我们需要框架?

引子:一个订单创建背后的两个世界 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 代码统计与问题分析 代码统计: ...

2025-11-03 · maneng

IoC容器深度解析:从手动new到自动装配的演进

引子:一个UserService的五种创建方式 假设你要创建一个UserService,它依赖UserRepository,而UserRepository又依赖DataSource。 这个看似简单的三层依赖,在不同的阶段有完全不同的创建方式: // 方式1:手动new(最原始) UserService userService = new UserService( new UserRepository( new DataSource("jdbc:mysql://localhost:3306/db", "root", "123456") ) ); // 方式2:工厂模式(稍好一点) UserService userService = UserServiceFactory.create(); // 方式3:依赖注入(手动装配) UserService userService = new UserService(); userService.setUserRepository(new UserRepository()); // 方式4:IoC容器(自动装配) ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); UserService userService = context.getBean(UserService.class); // 方式5:Spring Boot(零配置) @Autowired private UserService userService; // 自动注入 从方式1到方式5,到底发生了什么? 今天我们将通过5个渐进式场景,深度剖析IoC容器的演进逻辑,并亲手实现一个200行的简化版IoC容器。 一、场景0:手动new的噩梦(无容器) 1.1 三层依赖的手动创建 /** * 场景0:完全手动管理依赖 * 问题:硬编码、强耦合、难以测试 */ public class ManualDependencyDemo { public static void main(String[] args) { // 第1层:创建DataSource DataSource dataSource = new DataSource(); dataSource.setUrl("jdbc:mysql://localhost:3306/mydb"); dataSource.setUsername("root"); dataSource.setPassword("123456"); dataSource.setMaxPoolSize(10); // 第2层:创建UserRepository(依赖DataSource) UserRepository userRepository = new UserRepository(); userRepository.setDataSource(dataSource); // 第3层:创建UserService(依赖UserRepository) UserService userService = new UserService(); userService.setUserRepository(userRepository); // 使用 User user = userService.getUser(1L); System.out.println(user); } } /** * DataSource - 数据源 */ class DataSource { private String url; private String username; private String password; private int maxPoolSize; // getter/setter省略 } /** * UserRepository - 数据访问层 */ class UserRepository { private DataSource dataSource; public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } public User findById(Long id) { // 使用dataSource查询数据库 System.out.println("查询数据库,dataSource: " + dataSource); return new User(id, "张三"); } } /** * UserService - 业务逻辑层 */ class UserService { private UserRepository userRepository; public void setUserRepository(UserRepository userRepository) { this.userRepository = userRepository; } public User getUser(Long id) { return userRepository.findById(id); } } /** * User - 实体类 */ class User { private Long id; private String name; public User(Long id, String name) { this.id = id; this.name = name; } @Override public String toString() { return "User{id=" + id + ", name='" + name + "'}"; } } 1.2 核心问题分析 问题清单: ...

2025-11-03 · maneng

如约数科科技工作室

浙ICP备2025203501号

👀 本站总访问量 ...| 👤 访客数 ...| 📅 今日访问 ...