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

AOP深度解析:从代码重复到面向切面编程

引子:一个方法的六段重复代码 假设你要实现一个转账方法,按照传统方式,代码可能是这样的: public void transfer(String from, String to, BigDecimal amount) { // ========== 重复代码1:日志记录 ========== log.info("开始转账:{} -> {},金额:{}", from, to, amount); long startTime = System.currentTimeMillis(); try { // ========== 重复代码2:权限校验 ========== User currentUser = SecurityContext.getCurrentUser(); if (!currentUser.hasPermission("TRANSFER")) { throw new PermissionDeniedException("无转账权限"); } // ========== 重复代码3:参数校验 ========== if (amount.compareTo(BigDecimal.ZERO) <= 0) { throw new IllegalArgumentException("金额必须大于0"); } // ========== 重复代码4:事务管理 ========== Connection conn = dataSource.getConnection(); try { conn.setAutoCommit(false); // ========== 核心业务逻辑(只占20%) ========== Account fromAccount = accountDao.getByName(from); Account toAccount = accountDao.getByName(to); fromAccount.setBalance(fromAccount.getBalance().subtract(amount)); toAccount.setBalance(toAccount.getBalance().add(amount)); accountDao.update(fromAccount); accountDao.update(toAccount); // ============================================= conn.commit(); } catch (Exception e) { conn.rollback(); throw e; } finally { conn.close(); } } catch (Exception e) { // ========== 重复代码5:异常处理 ========== log.error("转账失败", e); throw new BusinessException("转账失败:" + e.getMessage()); } finally { // ========== 重复代码6:性能监控 ========== long endTime = System.currentTimeMillis(); log.info("转账完成,耗时:{}ms", endTime - startTime); } } 问题: ...

2025-11-03 · maneng

Java技术生态全景图:从JVM到微服务的完整技术栈深度解析

引子:一个请求背后的Java技术栈全貌 2025年某天上午10点,用户小王在电商平台下了一个订单,点击"提交订单"的那一刻,背后的Java技术栈开始运转: 0.01秒内发生的事情: Nginx 接收HTTP请求 → 转发到 Spring Cloud Gateway 网关 Gateway 鉴权(JWT) → Nacos 服务发现 → 路由到订单服务 订单服务(Spring Boot): Caffeine 本地缓存检查库存 MyBatis 查询 MySQL 订单信息 Redis 分布式锁防止超卖 RabbitMQ 发送消息到库存服务 库存服务 消费消息 → 扣减库存 → Elasticsearch 更新商品索引 支付服务 调用第三方支付接口 → Sentinel 限流熔断 全链路日志通过 SkyWalking 追踪 → 存储到 ClickHouse 这背后,涉及50+核心技术组件,组成了现代Java应用的完整生态。 今天我们就来系统化梳理这张技术全景图。 一、Java技术栈分层架构 1.1 完整分层视图 ┌─────────────────────────────────────────────────────────┐ │ 业务应用层(Business Layer) │ │ 电商平台、金融系统、物流平台、内容管理系统... │ └────────────────────┬────────────────────────────────────┘ │ ┌────────────────────┴────────────────────────────────────┐ │ 微服务治理层(Microservice Governance) │ │ 服务注册、配置中心、API网关、链路追踪、限流熔断... │ │ Spring Cloud、Dubbo、Nacos、Sentinel、SkyWalking │ └────────────────────┬────────────────────────────────────┘ │ ┌────────────────────┴────────────────────────────────────┐ │ 应用框架层(Application Framework) │ │ Spring Boot、Spring MVC、Spring Data、Spring Security │ │ MyBatis、Netty、Quartz、Shiro... │ └────────────────────┬────────────────────────────────────┘ │ ┌────────────────────┴────────────────────────────────────┐ │ 中间件与存储层(Middleware & Storage) │ │ MySQL、Redis、MongoDB、Elasticsearch、RabbitMQ、Kafka │ └────────────────────┬────────────────────────────────────┘ │ ┌────────────────────┴────────────────────────────────────┐ │ Java核心层(Core Java) │ │ JVM、并发包(JUC)、集合框架、IO/NIO、网络编程、反射... │ └─────────────────────────────────────────────────────────┘ 二、Java核心层:基石技术 2.1 JVM:Java虚拟机 JVM是Java生态的基石,理解JVM是从初级到高级的分水岭。 ...

2025-10-21 · maneng

如约数科科技工作室

浙ICP备2025203501号

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