云计算百科
云计算领域专业知识百科平台

Spring面试反杀指南:把IOC当婚介所,AOP当导演,事务当AA制

🔥 开场暴击:Spring面试三连问深度解析

"说说你对IOC的理解?" "AOP有哪些实现方式?" "Spring事务传播机制是什么?"

这些高频问题背后隐藏着面试官的三大考察维度:

  • 框架设计思想:是否理解解耦、动态代理等底层哲学

  • 实战应用能力:能否在项目中正确运用核心特性

  • 排错经验积累:是否踩过典型坑点并形成解决方案

  • "当for循环卡死在i++时,记得你还有递归这个选择。生活也是,直线走不通就换个维度思考" 。


    📦 第一章:IOC容器——对象治理体系(Spring的"对象婚介所")

    💡 面试官到底在问什么?

    当面试官问"IOC原理"时,其实是想考察:

  • 你是否理解"控制反转"的设计哲学

  • 能否说清楚容器如何管理Bean生命周期

  • 是否了解依赖注入的多种实现方式

  • 🎭 趣味类比版解释

    想象IOC容器是个智能婚介所:

    • 传统开发:程序员像焦虑的父母(new Object()到处给孩子找对象)

    • IOC模式:把子女的婚恋权交给婚介所(容器),父母只需声明需求(@Autowired)

    // 传统硬编码式相亲
    Person xiaoming = new Person();
    xiaoming.setPartner(new Person("小红"));
    // IOC式自由恋爱
    @Component
    public class Xiaoming {
    @Autowired
    // 婚介所自动匹配
    private Partner partner;
    }

    高频追问拆招

  • Bean作用域有哪些?

    • 单身狗(prototype):每次getBean都新建

    • 模范夫妻(singleton):全局唯一实例

    • 网恋对象(request/session):特定场景有效

  • 循环依赖怎么解决? 好比A和B互相暗恋,Spring的解决方案:

    • 三级缓存就像"传话机制"

    • 先给半成品对象(早期引用)

    • 等双方都准备好再正式"结婚"

  • 💡 高阶考察要点

    1.设计模式对比:

    • 传统工厂模式与IOC容器的自动化管理差异

  • ‌依赖管理方式不同‌

    • ‌工厂模式‌:需手动创建对象并管理依赖(如new UserDaoImpl()),调用者需主动获取依赖对象,导致代码耦合度高。若需更换实现类(如改用UserDaoMysqlImpl),必须修改源码。
    • ‌IOC容器‌:通过依赖注入(DI)自动管理依赖关系。对象仅需声明接口(如@Autowired UserDao),容器动态注入具体实现,无需修改业务代码即可切换实现类(如配置切换MySQL到Oracle驱动)。
  • ‌功能扩展性与生命周期管理‌

    • 工厂模式仅聚焦对象创建,资源初始化/销毁需手动处理,难以实现单例复用或作用域控制。
    • IOC容器统一管理对象生命周期(如单例/原型作用域),支持@PostConstruct初始化逻辑和AOP增强(如事务代理),提升资源利用率与扩展性。
    • 单例作用域下的线程安全保证机制

  • ‌饿汉式(预加载)‌ 类加载时直接初始化静态实例(private static final Singleton instance = new Singleton()),利用JVM类加载机制保证线程安全,但可能造成资源浪费。

  • ‌双重检查锁(DCL)‌ 结合volatile禁止指令重排与synchronized同步块,实现延迟加载且避免锁竞争:

    public class Singleton {
    private static volatile Singleton instance;
    public static Singleton getInstance() {
    if (instance == null) { // 第一次检查(无锁)
    synchronized (Singleton.class) { // 加锁
    if (instance == null) { // 第二次检查(避免重复创建)
    instance = new Singleton();
    }
    }
    }
    return instance;
    }
    }

    volatile确保多线程可见性,防止未完全初始化的对象逸出。

  • ‌静态内部类‌ 利用静态内部类首次调用时加载的特性(Holder类),实现懒加载与线程安全:

    public class Singleton {
    private static class Holder {
    static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
    return Holder.INSTANCE;
    }
    }

    无需同步锁,性能与安全性兼顾。

  • 关键差异总结:

    ‌维度‌‌工厂模式‌‌IOC容器‌
    依赖控制 调用者主动获取 容器被动注入(控制反转)
    可维护性 修改依赖需重构代码 仅调整配置,业务代码无侵入
    线程安全保障 需自行实现(如双重检查锁) 容器自动管理单例生命周期

    2.源码级辨析:

    // 组件注解的层级化设计
    @Controller // MVC请求处理入口
    @Service // 业务逻辑聚合层
    @Repository // 持久层异常转译器
    @Component // 通用组件基注解

    核心机制:控制反转与依赖注入

            IOC(控制反转)通过转移对象创建与依赖管理的控制权实现解耦。传统编码需主动new对象(正转),而IOC容器被动接管对象生命周期,按需注入依赖(反转)。

    源码实现的关键流程:

  • ‌Bean定义加载‌
    • 解析XML配置、注解或Java Config,将<bean>或@Bean转化为BeanDefinition对象(存储类路径、作用域等元数据)。
  • ‌实例化与依赖注入‌
    • 容器通过反射调用构造函数实例化Bean,再递归注入依赖(属性赋值或构造器参数)。
    • 依赖解析流程:检查字段@Autowired→查找匹配类型Bean→递归注入依赖链。

    // 简化的依赖注入伪代码
    void populateBean(Bean bean) {
    for (Field field : bean.getFields()) {
    if (field.isAnnotationPresent(Autowired.class)) {
    Object dependency = getBean(field.getType()); // 从容器获取依赖
    field.set(bean, dependency); // 反射注入
    }
    }
    }

  • ‌生命周期回调‌
    • 调用@PostConstruct初始化方法,支持InitializingBean接口或自定义init-method。

  • 与传统工厂模式的源码级差异

    ‌维度‌‌工厂模式‌‌IOC容器‌
    ‌对象创建‌ 硬编码new或静态工厂方法,耦合具体实现类 容器动态反射实例化,依赖接口而非实现类
    ‌依赖管理‌ 调用方主动获取依赖(Factory.getXxx()) 容器自动注入依赖(字段/构造器注入)
    ‌配置扩展‌ 修改依赖需重构源码 仅调整BeanDefinition(如XML→注解)

    依赖注入的源码实现方式

    IOC容器支持三种依赖注入模式(源码级实现差异):

            1.Setter注入‌

    通过BeanDefinition解析<property>标签或@Value,调用Setter方法赋值。

            2.构造器注入‌

    解析构造参数类型,按类型/名称匹配容器中Bean,优先用于强依赖场景。

            3.字段注入‌

    直接反射修改字段值(需@Autowired),但破坏封装性。

    Bean注册的高级机制

    Spring通过扩展点增强IOC灵活性:

    • ‌FactoryBean‌:动态生成代理对象(如Feign接口),容器实际存储FactoryBean.getObject()的返回值。
    • ‌ImportBeanDefinitionRegistrar‌:动态注册BeanDefinition(SpringBoot启动类核心)。
    • ‌ImportSelector‌:批量导入配置类,实现条件装配。

    线程安全的单例管理

    容器默认单例Bean通过‌双重检查锁与volatile‌ 保证线程安全:

    // 简化的单例Bean创建伪代码
    public Object getSingleton(String beanName) {
    Object bean = singletonCache.get(beanName);
    if (bean == null) {
    synchronized (this) {
    bean = singletonCache.get(beanName);
    if (bean == null) {
    bean = createBean(beanName); // 反射创建
    singletonCache.put(beanName, bean);
    }
    }
    }
    return bean;
    }

    依赖ConcurrentHashMap缓存单例,避免重复创建。

    ‌关键结论‌:IOC容器通过‌元数据驱动‌(BeanDefinition)、‌反射动态代理‌及‌并发控制‌,实现与传统工厂模式本质差异的解耦与自动化管理。

    3.性能优化实践:

    • @Lazy注解在依赖环场景下的应用

  • ‌依赖环问题本质‌ 当Bean A依赖Bean B,同时Bean B又依赖Bean A时,Spring默认的立即初始化策略会导致循环依赖异常。

  • ‌@Lazy的解决方案‌

    • 在任意一环添加@Lazy,延迟其中一个Bean的初始化,打破循环链: @Service
      public class ServiceA {
      @Autowired @Lazy // 延迟注入ServiceB
      private ServiceB serviceB;
      }

    • 底层通过代理对象临时占位,实际调用时触发目标Bean初始化。
  • ‌与作用域的协同‌

    作用域@Lazy效果
    Singleton 全局延迟到首次使用(仅一次初始化)
    Prototype 每次getBean()时新建(无优化意义)
  • ‌注意事项‌

    • 避免在@Configuration类中混用@Lazy与@Bean,可能导致代理层级混乱。
    • 依赖环场景下需确保至少一个Bean非延迟加载,否则可能引发BeanCurrentlyInCreationException。
    • BeanPostProcessor实现自定义初始化逻辑

  • 核心接口方法‌

    public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName);
    Object postProcessAfterInitialization(Object bean, String beanName);
    }

    • Before:在@PostConstruct之前执行,适合修改Bean属性。
    • After:在依赖注入完成后执行,适合代理增强。
  • ‌典型应用场景‌

    • ‌性能监控‌:统计Bean初始化耗时。
    • ‌动态代理‌:为特定接口生成AOP代理(如@Transactiona底层实现)。
    • ‌条件化装配‌:根据运行时状态决定是否注入依赖。
  • ‌实现示例‌

    public class CustomInitProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
    if (bean instanceof ExpensiveService) {
    return Proxy.newProxyInstance(…); // 生成延迟加载代理
    }
    return bean;
    }
    }

  • ‌与@Lazy的协同优化‌

    • 通过BeanPostProcessor动态识别高开销Bean并自动添加@Lazy等效逻辑。
    • 避免硬编码@Lazy,实现更灵活的延迟策略。
  • 综合优化建议

  • ‌依赖环优先使用构造器注入+@Lazy‌,而非setter注入,保持代码可测试性。
  • ‌BeanPostProcessor应注册为最高优先级‌(实现PriorityOrdered接口),确保早于其他处理器执行。
  • ‌生产环境监控‌:结合Spring Boot Actuator的/beans端点分析初始化顺序。
  • ️🌱生命周期管理图示

    graph LR:

          

    A[容器启动阶段] –> B[加载配置信息]

    B –> C[解析Bean定义 → BeanDefinition]

    C –> D[注册BeanDefinition到容器]

    D –> E[应用BeanFactoryPostProcessor]

    E –> F[Bean实例化阶段]

    F –> G[检查Bean作用域与缓存]

    G –> H[反射创建Bean实例]

    H –> I[依赖注入: @Autowired/@Resource]

    I –> J[Aware接口回调: BeanNameAware/BeanFactoryAware]

    J –> K[BeanPostProcessor前置处理]

    K –> L[初始化阶段]

    L –> M1[执行@PostConstruct] 

    L –> M2[InitializingBean.afterPropertiesSet]

    L –> M3[调用自定义init-method]

    L –> N[BeanPostProcessor后置处理]

    N –> O[Bean就绪 → 加入单例池]

    O –> P[运行期使用] P –> Q[容器关闭] Q –> R[销毁阶段] R –> S1[执行@PreDestroy] R –> S2[DisposableBean.destroy] R –> S3[调用自定义]  

    ️ ⚙配置规范建议

    • 反模式:混合注入方式引发的空指针问题

    • 最佳实践:强制依赖推荐使用构造器注入

    构造器注入强制规范

  • ‌核心优势‌

    • 保证依赖不可变(final修饰)
    • 避免NPE风险(容器启动时完成依赖检查)
    • 显式声明强依赖关系,提升代码可读性
  • ‌标准实现‌

    @Service
    public class OrderService {
    private final PaymentGateway gateway; // final确保不可变

    @Autowired // Spring 4.3+可省略
    public OrderService(PaymentGateway gateway) {
    this.gateway = gateway; // 依赖非空校验可在此执行
    }
    }

  • 混合注入反模式风险

  • ‌典型问题场景‌

    @Controller
    public class UserController {
    @Autowired // 字段注入
    private UserService userService;

    private AuditService auditService; // setter注入

    public void process() {
    auditService.log(); // NPE风险(未通过setter注入时)
    }

    @Autowired
    public void setAuditService(AuditService s) {
    this.auditService = s;
    }
    }

  • ‌风险点‌:字段注入与setter注入混用导致部分依赖未初始化

  • ‌解决方案‌

    • 统一使用构造器注入
    • 对可选依赖采用Optional包装或@Nullable注解
  • 高级配置建议

  • ‌循环依赖处理‌

    方案适用场景实现方式
    @Lazy 单例Bean循环引用 在构造参数添加@Lazy延迟初始化
    Setter/字段注入 不推荐(破坏不可变性) 仅作临时解决方案
  • ‌Bean作用域规范‌

    • 无状态服务使用Singleton(默认)
    • 有状态组件使用Prototype或请求级作用域
  • ‌AOP代理兼容性‌

    • 构造器注入天然支持JDK动态代理和CGLIB
    • 字段注入可能导致代理失效(尤其CGLIB)
  • 工程化检查策略

    ‌静态代码分析‌

    <!– SpotBugs规则示例 –>
    <dependency>
    <groupId>com.github.spotbugs</groupId>
    <artifactId>spotbugs-annotations</artifactId>
    <version>4.7.3</version>
    </dependency>

    检测@Autowired字段注入的使用

    ‌单元测试保障‌

    @SpringBootTest
    class OrderServiceTest {
    @Test
    void shouldThrowWhenDependencyNull() {
    assertThrows(BeanCreationException.class,
    () -> new OrderService(null));
    }
    }


    ✨ 第二章:AOP——非侵入式增强(代码界的"美颜相机")

    💡 灵魂之问:为什么要用AOP?

    当老板要求在所有方法加日志时:

    • OOP做法:每个方法里写log.info()(重复劳动)

    • AOP做法:声明"凡Controller层方法都要自动拍照留念"

    电影拍摄版理解

    把系统看作电影剧组:

    • 主演:核心业务逻辑(Service方法)

    • 替身:增强逻辑(Advice)

    • 导演:决定什么时候用替身(Pointcut)

    @Aspect
    public class LogAspect {
    // 定义拍摄时机:所有@GetMapping场景
    @Pointcut("@annotation(GetMapping)")
    public void logPointcut() {}
    // 开拍前打板(前置通知)
    @Before("logPointcut()")
    public void beforeAction(JoinPoint jp) {
    System.out.println("Action! Method: " + jp.getSignature());
    }
    }

    🎯 必知概念三连

  • JoinPoint:被拦截的"拍摄现场"

  • Advice:五种"特效处理":

    • @Before(开场白)

    • @After(杀青镜头)

    • @Around(全程跟拍)

    • @AfterReturning(完美收官)

    • @AfterThrowing(NG镜头)

  • 动态代理:

    • JDK代理:要求演员必须有接口(像签约艺人)

    • CGLIB:素人也能直接包装(继承方式)

  • 🔧 性能调优实战

    一、切面执行顺序控制
  • ‌多切面优先级管理‌

    @Aspect
    @Order(1) // 先执行
    public class LoggingAspect { … }

    @Aspect
    @Order(2) // 后执行
    public class SecurityAspect { … }

    • 使用@Order注解明确指定切面执行顺序(数值越小优先级越高)
    • 典型场景:验证切面需先于日志切面执行
  • ‌通知类型执行顺序‌

    单切面内:
    @Around → @Before → 目标方法
    → @AfterReturning/@AfterThrowing → @After → @Around

  •         环绕通知需手动调用proceed()触发后续流程

    二、切入点表达式优化
    • ‌表达式类型选择‌

      表达式类型适用场景性能影响
      execution() 精确匹配方法签名(包+类+方法) 高(需扫描字节码)
      @annotation() 通过注解标记目标方法 中(需反射检查)
      within() 匹配类级别 低(类加载时过滤)
    • ‌性能优化技巧‌

      • 避免宽泛匹配(如*.*(..)),限定到具体包路径
      • 复用切入点定义: @Pointcut("execution(* com.example.service.*.*(..))")
        public void serviceLayer() {}

        @Before("serviceLayer()")
        public void logBefore() { … }

      • 优先使用@annotation减少匹配范围
    三、代理机制调优
  • ‌强制CGLIB代理‌

    # 解决JDK动态代理需接口的限制
    spring.aop.proxy-target-class=true

    CGLIB性能开销略高但功能更全面

  • ‌切面懒加载‌

    @Aspect
    @Lazy // 延迟初始化切面实例
    public class HeavyAspect { … }

  • 四、实战案例:接口耗时监控
  • ‌自定义注解方案‌ @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface TrackExecutionTime {}

  • ‌高效切面实现‌ @Aspect
    @Component
    public class ExecutionTimeAspect {
    private static final Logger log = LoggerFactory.getLogger(ExecutionTimeAspect.class);

    @Around("@annotation(TrackExecutionTime)")
    public Object trackTime(ProceedingJoinPoint pjp) throws Throwable {
    long start = System.nanoTime();
    try {
    return pjp.proceed();
    } finally {
    log.debug("Method {} executed in {} ns",
    pjp.getSignature(), System.nanoTime() – start);
    }
    }
    }

    使用纳秒级计时减少误差

  • 五、常见陷阱规避
  • ‌Controller层切面优化‌

    • 避免直接拦截Controller类,改为增强Spring框架调用入口
    • 示例反模式: // 不推荐(性能敏感)
      @Before("execution(* com.example.web..*.*(..))")

  • ‌循环依赖处理‌

  •         切面依赖其他Bean时需配合@Lazy打破循环链

    📊 代理技术选型指南

    特性

    JDK动态代理

    CGLIB

    实现机制

    接口代理

    子类继承

    适用场景

    接口完备的系统

    遗留代码改造

    性能特点

    调用效率高

    生成速度快

    Spring策略

    默认方案

    补充方案

    💥 典型问题场景

    // 内部调用导致的代理失效
    public class PaymentService {
    public void process() { verifyAccount(); // 绕过事务代理 }

    @Transactional
    void verifyAccount() {…}
    }

    解决方案:通过ApplicationContext获取代理实例


    💼 第三章:事务管理——数据一致性保障(数据库界的"支付宝")

    ❓ 面试死亡问题:事务传播机制

    当被问到传播行为时,其实在考察:

  • 多个事务方法互相调用时的边界控制

  • 对ACID原则的实际应用能力

  • 聚餐买单类比

    把事务传播比作朋友聚餐:

    • REQUIRED(默认):有人买单就跟着吃,没人买就自己开单

    • REQUIRES_NEW:不管有没有人买单,自己另开一桌

    • NESTED:记子账单,主单失败就取消

    • NOT_SUPPORTED:AA制,不参与集体买单

    @Transactional(propagation = Propagation.REQUIRED)
    public void groupDinner() {
    // 如果已有事务就加入,没有就创建
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void privateRoom() {
    // 必须开新包间,不受外界影响
    }

    💣 事务失效的五大坑

  • 方法非public(包厢门锁了)

  • 自调用问题(自己叫自己吃饭)

  • 异常类型不匹配(吃出虫子但只说"不好吃")

  • 数据库引擎不支持(大排档没有发票)

  • 未启用事务管理(忘记带钱包)

  • 一、事务基础概念
  • ‌ACID特性‌

    • ‌原子性 (Atomicity)‌:事务内操作要么全部成功,要么全部失败回滚。
    • ‌一致性 (Consistency)‌:事务执行前后数据状态保持一致(如转账前后总金额不变)。
    • ‌隔离性 (Isolation)‌:并发事务间互不干扰,防止脏读、幻读等问题。
    • ‌持久性 (Durability)‌:事务提交后数据永久保存,即使系统故障也不丢失。
  • ‌隔离级别‌

    级别脏读不可重复读幻读适用场景
    READ_UNCOMMITTED 低一致性要求
    READ_COMMITTED 默认级别(Oracle)
    REPEATABLE_READ 默认级别(MySQL)
    SERIALIZABLE 强一致性场景

    通过@Transactional(isolation = Isolation.READ_COMMITTED) 指定。

  • ‌传播行为‌

    行为类型说明
    REQUIRED (默认) 当前存在事务则加入,否则新建事务
    REQUIRES_NEW 始终新建事务,挂起当前事务(独立提交/回滚)
    SUPPORTS 当前存在事务则加入,否则以非事务方式运行
    NOT_SUPPORTED 以非事务方式执行,挂起当前事务

  • 二、事务实现方式
  • ‌编程式事务‌

    TransactionTemplate template = …;
    template.execute(status -> {
    // 业务逻辑
    if (error) status.setRollbackOnly(); // 手动回滚
    return result;
    });

  • ‌缺点‌:代码侵入性强,需手动管理事务边界。

  • ‌声明式事务(推荐)‌

  • ‌注解驱动‌:

    @Transactional(
    propagation = Propagation.REQUIRED,
    rollbackFor = Exception.class // 指定异常回滚
    )
    public void updateData() { … }

    类级注解作用于所有public方法,方法级注解可覆盖类级配置。

    ‌XML配置‌:

    <tx:advice id="txAdvice">
    <tx:attributes>
    <tx:method name="update*" propagation="REQUIRED"/>
    </tx:attributes>
    </tx:advice>
    <aop:config>
    <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.service.*.*(..))"/>
    </aop:config>


    三、核心接口

    1‌.PlatformTransactionManager‌

            事务管理核心接口(如DataSourceTransactionManager、JpaTransactionManager)。

    2‌.TransactionDefinition‌

            定义事务属性(传播行为、隔离级别、超时等)。

    3‌.TransactionStatus‌

            事务运行时状态(是否回滚、是否完成)。


    四、疑难解决方案
    问题原因解决方案
    ‌事务未生效‌ 方法非public 仅public方法支持事务代理
    ‌异常未回滚‌ 默认仅回滚RuntimeException 添加@Transactional(rollbackFor = Exception.class)
    ‌跨方法调用失效‌ 同类内非代理调用 通过AOP上下文调用或拆分到不同类
    ‌数据库不支持‌ 如MySQL的MyISAM引擎 切换为InnoDB引擎

    五、最佳实践

            1‌.统一异常回滚‌:

    @Transactional(rollbackFor = Exception.class) // 覆盖所有异常类型
    ```:ml-citation{ref="3" data="citationList"}

            2‌.精简事务范围‌:

            避免在事务内执行耗时操作(如网络调用)。

            3.读写分离优化‌:

            只读查询使用@Transactional(readOnly = true)提升性能。

            4‌.传播行为谨慎选择‌:

            多数据更新用REQUIRED,独立日志记录用REQUIRES_NEW。


    💥第四章: 高阶反杀战术库

    一、IOC容器の死亡追问

    情景模拟:当面试官说"BeanFactory和ApplicationContext区别讲一下"

    • 🔥 标准答案:基础婚介所 vs 豪华婚恋中心(支持国际婚姻、婚前培训等增值服务)

    • 反杀连招:

    // 追问1:为什么ApplicationContext要预初始化Bean?
    // 答:就像婚介所提前审核会员资料(加载配置时创建对象),
    // 避免相亲现场才查户口(延迟加载导致性能波动)

    // 追问2:FactoryBean的特殊性?
    // 答:这不是普通红娘,是红娘培训师(能生产特殊对象),getObject()就是毕业典礼

    二、AOPの陷阱拆解

    高频翻车题:"JDK动态代理和CGLIB如何选择?"

    • 🎭 表演学派解释:

    • JDK代理:要求演员必须有经纪公司(接口)

    • CGLIB:素人出道也能捧红(直接继承目标类)

    • 💣 隐藏考点:

    # 陷阱:final类为什么不能用CGLIB?
    # 答:就像给已绝育的猫配种(无法生成子类),建议改用JDK代理或重组基因(重构代码)

    三、事务の绝地反击

    死亡场景:"@Transactional失效的N种姿势"

    • 翻车大全: 

    作死行为  科学解释 抢救方案
    自调用 自家AA制不算数(非代理调用) 拆家分灶(拆分类)
    异常类型不匹配 只认发票不认收据 @Transactional(rollbackFor=Exception.class)
    非public方法 私房钱不参与家庭记账 改用AspectJ模式

    终极大杀器:源码级反问

    当面试官露出满意表情时,突然抛出:

  • "Spring如何解决循环依赖的三级缓存?"

    参考答案:就像婚介所调解三角恋,一级缓存(结婚证)、二级缓存(订婚协议)、三级缓存(相亲资料)

  • "AOP的Advice执行顺序如何控制?"

    神回复:导演喊卡的优先级,@Order(1)比@Order(2)先喊cut


  • 🎁第六章、彩蛋

    彩蛋升级:Spring面试避坑指南

    陷阱类型

    典型案例

    解决方案

    配置陷阱

    @Transactional未生效

    检查代理模式与异常类型

    性能陷阱

    过度AOP导致链路变长

    使用条件切面(@Conditional)

    并发陷阱

    单例Bean中的成员变量

    改用ThreadLocal存储

    测试陷阱

    单元测试污染Spring上下文

    使用@MockBean隔离依赖

    Spring面试速查表

    概念

    记忆口诀

    典型问题

    IOC

    "不用new,等注入"

    Bean生命周期/循环依赖

    AOP

    "动态代理+切面=解耦"

    通知类型/动态代理区别

    事务

    "ACID+传播+隔离=安全"

    传播行为/失效场景

    调试不是失败,而是成长的必经之路。每一次解决bug,都是在积累经验。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Spring面试反杀指南:把IOC当婚介所,AOP当导演,事务当AA制
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!