告别只会 CRUD!Spring 核心原理吃透,这一篇就够了(Java 程序员必藏)

作为 Java 开发者,你一定绕不开 Spring------ 它不是简单的工具类,而是统治 Java 企业级开发近 20 年的 "开发圣经"。

很多人学 Spring,只停留在 "会用 @Autowired、@Service" 的层面,面试被问 "Spring IoC 原理""循环依赖怎么解决""AOP 底层实现",瞬间卡壳;开发时遇到 Bean 注入失败、事务不生效,只能瞎猜乱试。

这篇文章,不跳步、不玄学、不堆砌概念,用 "道法术器" 四层逻辑,从 "为什么要有 Spring" 到 "Spring 生态怎么用",把 Spring 彻底讲透。全程专业准确,新手能入门,老手能查漏补缺,建议立刻收藏,面试、开发、复盘都能直接翻。


第一步:问题的原点 ------ 为什么要有 Spring?(先搞懂 "为什么",再学 "怎么用")

想象你是 Java 开发者,要开发一个电商系统,用户下单时需要扣库存、生成订单、发送短信。按传统方式写代码,会陷入 5 个致命坑:

java

运行

java 复制代码
public class OrderService {
    // 直接new依赖,耦合死死的
    private InventoryService inventoryService = new InventoryService();
    private SmsService smsService = new SmsService();
    
    public void createOrder(Order order) {
        inventoryService.deductStock(order);  // 扣库存
        // 保存订单到数据库...
        smsService.sendNotification(order);   // 发短信
    }
}

传统开发的 5 大痛点(戳中所有 Java 开发者的泪点)

  1. 耦合太紧:OrderService 直接依赖 InventoryService、SmsService 的具体实现,想把阿里云短信换成腾讯云,必须修改 OrderService 代码,牵一发而动全身;
  2. 难以测试:测试 OrderService 时,必须创建真实的 InventoryService(会真扣库存)、SmsService(会真发短信),单元测试变成集成测试,慢且不稳定;
  3. 对象生命周期混乱:谁创建对象?什么时候创建?OrderService 该是单例还是多例?这些细节散落在代码各处,后期维护一团糟;
  4. 代码臃肿:每个方法都要写日志、事务管理、权限检查,这些和业务无关的 "横切代码",把核心业务逻辑埋得严严实实;
  5. 配置分散:数据库连接、线程池大小、缓存策略全硬编码在类里,改一个配置要改多处,部署上线全是坑。

核心结论

Spring 存在的唯一理由:让开发者只专注核心业务逻辑,把 "对象创建、依赖管理、横切关注点处理" 这些基础设施问题,全部交给框架来做


第二步:道的层面 ------Spring 的根本思想(懂道,才懂 Spring 的设计精髓)

"道" 是 Spring 的灵魂,回答 "为什么这么设计",搞懂这 4 个思想,就抓住了 Spring 的本质。

道 1:控制反转(IoC)------ 把控制权交出去(核心中的核心)

传统编程:对象自己 "掌控一切"------ 自己创建依赖、自己管理生命周期,比如 "我要用到 A,就自己 new A ()"。

java

运行

less 复制代码
A a = new A();  // 我自己创建,自己控制
a.doSomething();

这叫 "正转"------ 控制权在你手里。

控制反转(IoC):把对象的创建、依赖管理权力,从对象本身转移到 Spring 容器。你只管声明 "我需要什么",容器负责 "给你什么",不用自己动手 new。

java

运行

kotlin 复制代码
@Service  // 告诉Spring:我是一个Bean,交给你管理
public class OrderService {
    @Autowired  // 告诉Spring:我需要一个InventoryService,你给我注入
    private InventoryService inventoryService;
}

✅ 为什么叫 "反转"?因为控制权从 "开发者 / 对象",转移到了 "Spring 容器"。

道 2:依赖注入(DI)------IoC 的具体实现(落地层面)

控制反转是 "思想",依赖注入是 "落地方式":Spring 容器在创建对象时,自动把依赖的对象 "注入" 到当前对象中,不用你手动赋值。

Spring 支持 3 种注入方式(重点记推荐用法):

  • 构造器注入(Spring 推荐):通过构造函数传入依赖,依赖不可变(final)、不能为 null,便于单元测试;
  • Setter 注入:通过 setter 方法设置依赖,适合可选依赖;
  • 字段注入(常用但不推荐):直接给字段赋值,代码简洁,但可读性差、难以测试。

道 3:面向切面编程(AOP)------ 分离横切关注点(解耦关键)

日志、事务、安全、缓存这些 "横切关注点",横切于多个业务模块,若散落在各处,会导致代码重复、维护困难。

AOP 的核心思想:把横切关注点封装成 "切面",在运行时 "织入" 到业务代码中,不修改业务代码本身,实现 "业务代码和非业务代码分离"。

java

运行

typescript 复制代码
@Transactional  // 声明式事务,不用写一行事务管理代码
public void transferMoney(Account from, Account to, BigDecimal amount) {
    // 只写核心业务逻辑,事务由Spring自动管理
    from.deduct(amount);
    to.add(amount);
}

✅ 好处:业务代码更纯粹,横切逻辑可复用、可维护。

道 4:非侵入式设计(Spring 的 "温柔" 之处)

Spring 的核心理念:你的业务类就是普通的 Java 对象(POJO),不需要继承 Spring 的特定类、实现 Spring 的特定接口

java

运行

arduino 复制代码
// 普通Java类,没有任何Spring相关代码
public class OrderService {
    private InventoryService inventoryService;
    
    // 普通构造器
    public OrderService(InventoryService inventoryService) {
        this.inventoryService = inventoryService;
    }
    
    // 普通业务方法
    public void createOrder(Order order) {
        inventoryService.deductStock(order);
    }
}

这个类可以在 Spring 中使用,也可以单独测试、单独使用,完全不受框架约束 ------ 这就是 Spring 的 "非侵入式",不绑架你的代码。


第三步:法的层面 ------Spring 的核心方法论(懂法,才会用对 Spring)

"法" 是实现 "道" 的路径和方法论,回答 "怎么做",这 4 个方法论,是 Spring 的核心骨架。

法 1:Bean 的生命周期管理(Spring 怎么管理对象)

Spring 容器会全程管理 Bean 的生命周期,从创建到销毁,一步不落地:

plaintext

java 复制代码
实例化(new对象)→ 属性赋值(注入依赖)→ 初始化(@PostConstruct)→ 使用 → 销毁(@PreDestroy)

关键亮点:Spring 提供多个扩展点,让你可以在生命周期的不同阶段插入自定义逻辑:

  • BeanPostProcessor:在 Bean 初始化前后做自定义处理(比如修改 Bean 属性);
  • @PostConstruct:Bean 初始化完成后执行;
  • @PreDestroy:Bean 销毁前执行(比如释放资源)。

法 2:依赖解析与注入机制(Spring 怎么找到要注入的 Bean)

Spring 不是 "瞎注入",而是有一套明确的依赖解析规则:

  1. 类型匹配:默认按 "字段类型" 或 "构造器参数类型",查找容器中对应的 Bean;
  2. 名称匹配:通过 @Qualifier 或 @Resource (name=...),指定要注入的 Bean 名称;
  3. 自动装配:@Autowired 默认按类型装配,找到多个匹配 Bean 时,会按 Bean 名称匹配。

重点:三级缓存解决循环依赖(面试高频)

当 A 依赖 B、B 依赖 A 时(循环依赖),Spring 用 "三级缓存" 完美解决,不用手动处理:

  • 一级缓存(singletonObjects):存放 "成品 Bean"(已实例化、已初始化、可直接使用);
  • 二级缓存(earlySingletonObjects):存放 "半成品 Bean"(已实例化、未初始化,提前暴露的引用);
  • 三级缓存(singletonFactories):存放 "Bean 工厂",用于提前暴露 Bean 的引用。

循环依赖解决流程(极简版):

  1. 创建 A,将 A 的工厂放入三级缓存;
  2. A 需要 B,Spring 去创建 B;
  3. B 需要 A,从三级缓存拿到 A 的工厂,获取 A 的半成品引用(放入二级缓存);
  4. B 创建完成(成品),放入一级缓存;
  5. A 拿到 B 的引用,完成初始化,成为成品,放入一级缓存。

法 3:代理机制与 AOP 实现(AOP 的底层原理)

Spring AOP 的底层是 "动态代理",根据目标对象是否实现接口,选择不同的代理方式:

  • JDK 动态代理:如果目标对象实现了接口,用 JDK 的 Proxy 类生成代理对象(代理接口);
  • CGLIB 代理:如果目标对象没有实现接口,用 CGLIB 生成目标类的子类(代理类)。

核心逻辑(伪代码,一看就懂):

java

运行

scss 复制代码
public class AopProxyFactory {
    public Object createProxy(Object target, Advice advice) {
        // 目标对象有接口 → JDK动态代理
        if (target.getClass().getInterfaces().length > 0) {
            return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                (proxy, method, args) -> {
                    advice.before();  // 切面逻辑(比如日志)
                    Object result = method.invoke(target, args);  // 业务逻辑
                    advice.after();   // 切面逻辑(比如事务提交)
                    return result;
                }
            );
        } else {
            // 目标对象无接口 → CGLIB代理
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(target.getClass());
            enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
                advice.before();
                Object result = proxy.invokeSuper(obj, args);
                advice.after();
                return result;
            });
            return enhancer.create();
        }
    }
}

法 4:声明式编程范式(Spring 的高效用法)

Spring 鼓励 "声明式编程",通过注解或 XML 声明配置,代替硬编码,让代码更简洁、可维护。

java

运行

kotlin 复制代码
// 声明配置类
@Configuration  // 告诉Spring:这是一个配置类
@ComponentScan("com.example")  // 声明扫描哪些包的Bean
public class AppConfig {
    @Bean  // 声明一个Bean,交给Spring管理
    public DataSource dataSource() {
        return new HikariDataSource();
    }
}

// 声明Service Bean + 事务
@Service  // 声明这是一个Service层Bean
@Transactional  // 声明该类所有方法都需要事务管理
public class UserService {
    // 只写业务逻辑,配置由Spring管理
}

✅ 声明式编程的好处:关注点分离(业务归业务,配置归配置)、可维护性强、修改配置不用改业务代码。


第四步:术的层面 ------Spring 的具体技术实现(懂术,才能解决实际问题)

"术" 是具体的技术技巧,回答 "用什么工具实现",掌握这些,遇到 Spring 相关问题能快速定位、解决。

术 1:ApplicationContext 的 12 步启动流程(Spring 容器怎么启动)

Spring 容器(ApplicationContext)的启动是一个精密的流程,掌握它,能轻松排查 "容器启动失败" 问题:

  1. 准备上下文:设置环境变量、加载配置文件;
  2. 读取配置:加载 @Configuration 类或 XML 配置;
  3. 解析 Bean 定义:将配置解析为 BeanDefinition(Bean 的 "说明书");
  4. 注册 Bean 后置处理器:准备 BeanFactoryPostProcessor(用于修改 Bean 定义);
  5. 实例化 Bean:创建非懒加载的单例 Bean 实例;
  6. 属性填充:为 Bean 注入依赖;
  7. 初始化:调用 @PostConstruct 或 InitializingBean 的初始化方法;
  8. 注册销毁回调:为需要销毁的 Bean 注册销毁逻辑;
  9. 发布事件:通知所有监听器 "容器已刷新";
  10. 完成刷新:容器启动完成,可正常使用;
  11. 处理懒加载 Bean:用到时再创建;
  12. 销毁:容器关闭时,执行 Bean 的销毁方法,释放资源。

术 2:各种注入方式的底层实现(@Autowired 到底怎么用)

1. 构造器注入(推荐)

java

运行

arduino 复制代码
// 构造器注入
public OrderService(InventoryService inventoryService) {
    this.inventoryService = inventoryService;
}

底层原理:Spring 通过反射找到该构造器,从容器中获取 InventoryService 实例,传入构造器创建 OrderService。

2. 字段注入(常用)

java

运行

java 复制代码
@Autowired
private InventoryService inventoryService;

底层原理:Spring 通过反射获取该私有字段,设置 setAccessible (true)(突破私有访问限制),直接将容器中的 Bean 赋值给字段。

术 3:AOP 的切面表达式(精准匹配需要增强的方法)

Spring AOP 使用 AspectJ 的切点表达式,常用 3 种表达式,直接复制可用:

java

运行

java 复制代码
@Aspect
@Component
public class LoggingAspect {
    // 1. execution表达式:匹配指定包下的所有方法(最常用)
    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore() {
        System.out.println("方法执行前,打印日志");
    }
    
    // 2. @annotation表达式:匹配有特定注解的方法
    @Around("@annotation(com.example.annotation.Loggable)")
    public Object logAround(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = pjp.proceed();  // 执行原方法
        long duration = System.currentTimeMillis() - start;
        System.out.println("方法执行耗时:" + duration + "ms");
        return result;
    }
    
    // 3. within表达式:匹配指定包及子包下的所有方法
    @AfterReturning("within(com.example.controller..*)")
    public void logAfterReturning() {
        System.out.println("方法正常返回,打印日志");
    }
}

术 4:事务管理机制(@Transactional 为什么能生效)

Spring 事务的核心是 @Transactional 注解和 TransactionInterceptor(事务拦截器),底层流程如下:

  1. TransactionInterceptor 拦截被 @Transactional 标注的方法;
  2. 根据 @Transactional 的属性(传播行为、隔离级别等),从 PlatformTransactionManager 获取事务;
  3. 执行业务方法;
  4. 若方法正常执行,提交事务;若抛出异常(符合 rollbackFor 配置),回滚事务;
  5. 清理事务资源。

常用 @Transactional 属性(开发必记):

java

运行

ini 复制代码
@Transactional(
    propagation = Propagation.REQUIRED,  // 事务传播行为(默认,有事务则加入,无则新建)
    isolation = Isolation.READ_COMMITTED, // 隔离级别(默认,避免脏读)
    timeout = 30,                          // 超时时间(30秒,超时回滚)
    rollbackFor = RuntimeException.class   // 哪些异常触发回滚(默认只回滚运行时异常)
)

第五步:器的层面 ------Spring 生态的工具箱(懂器,才能高效开发)

"器" 是 Spring 的具体工具和组件,回答 "有哪些东西可以用",Spring 生态极其完善,开箱即用,覆盖开发全场景。

器 1:Spring Framework 核心模块(基础中的基础)

表格

模块 核心功能 核心类 / 接口
spring-core IoC 容器基础,提供核心工具类 BeanFactory, ApplicationContext
spring-beans Bean 的创建、管理、依赖注入 BeanDefinition, BeanWrapper
spring-aop 面向切面编程,提供 AOP 实现 ProxyFactory, AspectJProxyFactory
spring-context 容器上下文、事件机制、资源管理 ApplicationEvent, ResourceLoader
spring-tx 事务管理,支持声明式 / 编程式事务 PlatformTransactionManager, @Transactional
spring-web Web 开发基础,整合 Servlet DispatcherServlet, HandlerMapping
spring-webmvc Spring MVC 实现,用于 Web 开发 @Controller, @RequestMapping
spring-jdbc JDBC 抽象,简化数据库操作 JdbcTemplate, NamedParameterJdbcTemplate

器 2:Spring Boot(简化 Spring 部署,一键启动)

Spring Boot 的核心是 "自动配置",解决了 Spring "配置繁琐" 的痛点,只需一个注解,就能快速启动 Spring 应用:

java

运行

typescript 复制代码
@SpringBootApplication  // 组合注解:@Configuration + @EnableAutoConfiguration + @ComponentScan
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args); // 一键启动
    }
}

自动配置原理:

  1. @EnableAutoConfiguration 导入 AutoConfigurationImportSelector;
  2. 扫描 META-INF/spring.factories 文件,加载所有 AutoConfiguration 类;
  3. 根据条件注解(@ConditionalOnClass、@ConditionalOnBean 等),判断配置是否生效。

器 3:Spring Cloud(微服务开发套件)

Spring Cloud 基于 Spring Boot,提供微服务开发的全套组件,解决微服务中的服务发现、网关、链路追踪等问题:

表格

组件 核心功能
Spring Cloud Config 分布式配置中心,统一管理配置
Spring Cloud Netflix 服务发现(Eureka)、断路器(Hystrix)
Spring Cloud Gateway API 网关,统一入口、路由转发
Spring Cloud Sleuth 链路追踪,排查微服务调用问题
Spring Cloud Stream 消息驱动,简化消息队列使用

器 4:Spring Data(简化数据访问)

Spring Data 统一了各类数据访问框架的 API,只需定义接口,Spring 自动实现 CRUD 方法,不用写 SQL:

java

运行

java 复制代码
// 继承JpaRepository,自动获得CRUD、分页、排序等方法
public interface UserRepository extends JpaRepository<User, Long> {
    // 方法名解析为SQL:SELECT * FROM user WHERE last_name = ?
    List<User> findByLastName(String lastName);
    
    // 自定义JPQL查询
    @Query("SELECT u FROM User u WHERE u.email = ?1")
    User findByEmail(String email);
}

器 5:Spring Security(安全框架)

Spring Security 提供身份认证、授权、防攻击等功能,快速实现系统安全:

java

运行

scala 复制代码
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll() // 公开接口,无需登录
                .antMatchers("/admin/**").hasRole("ADMIN") // 管理员才能访问
                .anyRequest().authenticated() // 其他接口需登录
                .and()
            .formLogin()
                .loginPage("/login") // 自定义登录页
                .permitAll();
    }
}

第六步:用简单比喻理解 Spring(道法术器全打通)

很多人觉得 Spring 复杂,其实用 "一家大型餐厅" 的比喻,就能轻松理解道法术器四层逻辑:

道的层面:餐厅的经营理念

  • 控制反转(IoC):你不自己买菜、做饭,坐在餐桌前点菜,厨师(Spring 容器)给你做好端上来;
  • 依赖注入(DI):你只需说 "我要一杯水",服务员(Spring)就把水给你倒好(注入),不用自己去后厨找;
  • 面向切面(AOP):服务员会在你用餐前铺餐巾、用餐后结账,这些服务(横切关注点)不用你操心;
  • 非侵入式:你坐在餐厅里还是你自己,不用穿餐厅制服、不用考厨师证(不用继承 Spring 类)。

法的层面:餐厅的运营流程

  • Bean 生命周期:客人进店(实例化)→ 点菜(属性赋值)→ 上菜(初始化)→ 用餐(使用)→ 离店(销毁);
  • 依赖解析:服务员根据你点的菜,知道该去哪个窗口取(类型匹配);
  • 动态代理:传菜员(代理)把菜从后厨端到桌前,你只管吃(不用关心菜怎么来的)。

术的层面:餐厅的操作技巧

  • ApplicationContext 启动:餐厅开业准备 ------ 打扫卫生(准备环境)、摆桌椅(创建 Bean)、检查食材(验证配置)、开门迎客(发布事件);
  • 依赖注入方式:构造器注入(进门就给菜单)、Setter 注入(坐下再递菜单)、字段注入(直接上你爱吃的菜);
  • AOP 表达式:告诉服务员 "哪些桌需要提前铺餐巾"(切点匹配)。

器的层面:餐厅的工具设备

  • Spring Framework:餐厅的基础设施(桌椅、厨房、餐具);
  • Spring Boot:连锁餐厅的标准化开店流程,一键开业;
  • Spring Cloud:餐饮集团,管理多家分店(微服务);
  • Spring Data:食材管理系统,标准化采购(数据访问);
  • Spring Security:门禁系统,区分普通客人和 VIP(权限控制)。

第七步:Spring 的本质是什么?(第一性原理总结)

用第一性原理来看,Spring 的本质是:一个通过 IoC 容器和 AOP 机制,实现 Java 应用松耦合、可测试、易维护的企业级应用开发框架

它的核心哲学,就是 "道法术器" 四层体系:

  • 道:指引方向(为什么设计)------ 解决耦合、测试、横切关注点问题;
  • 法:提供路径(怎么设计)------ 通过生命周期、依赖解析、代理机制实现;
  • 术:给出技巧(怎么实现)------ 启动流程、注入方式、事务拦截等具体技术;
  • 器:提供工具(用什么实现)------Spring Boot、Cloud、Data 等生态组件。

这就是 Spring 能统治 Java 近 20 年的根本原因:它不仅是一个框架,更是一套完整的思想体系和开发方法论。


总结:Spring 道法术器速查表(收藏备用)

表格

层次 核心内容 一句话总结
IoC、DI、AOP、非侵入式 把控制权交出去,只专注核心业务
生命周期、依赖解析、代理机制、声明式编程 规范对象管理和依赖注入的流程
启动流程、注入技巧、AOP 表达式、事务拦截 解决 Spring 开发中的具体技术问题
Spring Boot、Cloud、Data、Security 开箱即用的生态工具,提升开发效率

🔥 互动话题

学 Spring 时,你最头疼的问题是什么?

  • 循环依赖搞不懂
  • AOP 底层代理机制绕不明白
  • @Transactional 事务不生效
  • Spring Boot 自动配置踩坑
  • 面试被问 Spring 原理答不上来

评论区留下你的痛点,我会挑高频问题,下期专门出《Spring 常见坑排查实战》,手把手教你解决,还会附赠 Spring 面试高频题合集!

相关推荐
我爱娃哈哈1 小时前
Spring AI Alibaba 教程:集成阿里云大模型服务实战
后端
Moe4881 小时前
基于 AOP 与 Redisson 的分布式锁实现:自动加锁、解锁与 SpEL 参数解析
java·后端·架构
vx-程序开发1 小时前
springboot名士会所会员管理系统-计算机毕业设计源码57546
spring boot·后端·课程设计
敲代码的嘎仔2 小时前
Java后端开发——Redis面试题汇总
java·开发语言·redis·学习·缓存·面试·职场和发展
啦啦啦_99992 小时前
4. AI面试题之 Prompt
java·prompt
YmaxU2 小时前
SpringAIAlibaba学习使用 ---核心API、RAG、Tool Calling
java·学习·spring·ai
泉城老铁2 小时前
springboot 项目jar 如何部署到docker
后端
AMoon丶2 小时前
C++基础-类、对象
java·linux·服务器·c语言·开发语言·jvm·c++
Thomas.Sir2 小时前
SpringBoot 3 集成 Sleuth + zipkin 实现微服务链路追踪
spring·spring cloud·微服务·sleuth·zipkin·日志追踪