Spring第48篇:@Transaction 源码深度解析

Spring @Transaction源码解析:AOP与自动事务管理机制
本文详细剖析了Spring框架中@Transaction注解的事务管理原理,涉及AOP、TransactionInterceptor拦截器和@EnableTransactionManagement配置。通过源码解读,揭示了事务开启、回滚与提交的决策逻辑。

大家好,今天咱们通过源码来了解一下spring中@Transaction事务的原理。

开始本文之前,下面这些知识需提前了解下

1、吃透Spring AOP

2、Spring编程式事务源码解析

在这里插播两句,整个系列前后知识是有依赖的,大家最好按顺序阅读,这样不会出现无法理解的情况,若跳着读,可能会比较懵。。。

1、环境

  1. jdk1.8

  2. Spring版本:5.2.3.RELEASE

  3. mysql5.7

2、@Transaction 事务的用法

咱们先来回顾一下,@Transaction 事务的用法,特别简单,2个步骤

1、在需要让spring管理事务的方法上添加 @Transaction 注解

2、在spring配置类上添加 @EnableTransactionManagement 注解,这步特别重要,别给忘了,有了这个注解之后,@Trasaction标注的方法才会生效。

3、@Transaction事务原理

原理比较简单,内部是通过spring aop的功能,通过拦截器拦截 @Transaction 方法的执行,在方法前后添加事务的功能。

4、@EnableTransactionManagement注解作用

@EnableTransactionManagement注解会开启spring自动管理事务的功能,有了这个注解之后,spring容器启动的过程中,会拦截所有bean的创建过程,判断bean 是否需要让spring来管理事务,即判断bean中是否有@Transaction注解,判断规则如下

1、一直沿着当前bean的类向上找,先从当前类中,然后父类、父类的父类,当前类的接口、接口父接口,父接口的父接口,一直向上找,一下这些类型上面是否有 @Transaction注解

2、类的任意public方法上面是否有@Transaction注解

如果bean满足上面任意一个规则,就会被spring容器通过aop的方式创建代理,代理中会添加一个拦截器

org.springframework.transaction.interceptor.TransactionInterceptor

TransactionInterceptor 拦截器是关键,它会拦截@Trasaction方法的执行,在方法执行前后添加事务的功能,这个拦截器中大部分都是编程式事务的代码,若 编程式事务的源码 大家看懂了,这个拦截器源码看起来就是小儿科了。

5、@EnableTransactionManagement源码解析

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class) //@1
public @interface EnableTransactionManagement {

 // 是基于类的代理(cglib),还是基于接口的代理(jdk动态代理),默认为false,表示是基于jdk动态代理
 boolean proxyTargetClass() default false;
    
    //通知的模式,默认是通过aop的方式
    AdviceMode mode() default AdviceMode.PROXY;

 // 我们知道这个注解的功能最终是通过aop的方式来实现的,对bean创建了一个代理,代理中添加了一个拦截器
    // 当代理中还有其他拦截器的是时候,可以通过order这个属性来指定事务拦截器的顺序
    // 默认值是 LOWEST_PRECEDENCE = Integer.MAX_VALUE,拦截器的执行顺序是order升序
 int order() default Ordered.LOWEST_PRECEDENCE;

}

注意@1这个代码

@Import(TransactionManagementConfigurationSelector.class)

用到了@Import注解,对这个注解不熟悉的可以看一下Spring系列第19篇:@import详解(bean批量注册),这个注解的value是TransactionManagementConfigurationSelector,看一下这个类的源码,重点是他的selectImports方法,这个方法会返回一个类名数组,spring容器启动过程中会自动调用这个方法,将这个方法指定的类注册到spring容器中;方法的参数是AdviceMode,这个就是@EnableTransactionManagement注解中mode属性的值,默认是PROXY,所以会走到@1代码处

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

 @Override
 protected String[] selectImports(AdviceMode adviceMode) {
  switch (adviceMode) {
   case PROXY: //@1
    return new String[] {AutoProxyRegistrar.class.getName(),
      ProxyTransactionManagementConfiguration.class.getName()};
   case ASPECTJ:
    return new String[] {determineTransactionAspectClass()};
   default:
    return null;
  }
 }

}

最终会在spirng容器中注册下面这2个bean

AutoProxyRegistrar
ProxyTransactionManagementConfiguration

下面来看一下这2个类的代码。

AutoProxyRegistrar

这个类实现了ImportBeanDefinitionRegistrar接口,这个接口中有个方法registerBeanDefinitions,spring容器在启动过程中会调用这个方法,开发者可以在这个方法中做一些bean注册的事情,而AutoProxyRegistrar在这个方法中主要做的事情就是下面@1的代码,大家可以点进去看看,这里我就不点进去了,这个代码的作用就是在容器中做了一个非常关键的bean:InfrastructureAdvisorAutoProxyCreator,这个类之前在aop中介绍过,是bean后置处理器,会拦截所有bean的创建,对符合条件的bean创建代理。

public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

 @Override
 public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
  boolean candidateFound = false;
  Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
  for (String annType : annTypes) {
   AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
   if (candidate == null) {
    continue;
   }
   Object mode = candidate.get("mode");
   Object proxyTargetClass = candidate.get("proxyTargetClass");
   if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
     Boolean.class == proxyTargetClass.getClass()) {
    candidateFound = true;
    if (mode == AdviceMode.PROXY) {
     AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);//@1
     if ((Boolean) proxyTargetClass) {
      AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
      return;
     }
    }
   }
  }
 }
}

说的简单点:AutoProxyRegistrar的作用就是启用spring aop的功能,对符合条件的bean创建代理。

ProxyTransactionManagementConfiguration

@Configuration(proxyBeanMethods = false)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
 //注册bean:事务顾问(spring aop中拦截器链就是一个个的Advisor对象)
 @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
 @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
 public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
   TransactionAttributeSource transactionAttributeSource,
   TransactionInterceptor transactionInterceptor) {
  BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
  advisor.setTransactionAttributeSource(transactionAttributeSource);
        //设置事务拦截器
  advisor.setAdvice(transactionInterceptor);
  if (this.enableTx != null) {
            //设置aop中事务拦截器的顺序
   advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
  }
  return advisor;
 }

    //注册bean:TransactionAttributeSource,TransactionAttributeSource用来获取获取事务属性配置信息:TransactionAttribute
 @Bean
 @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
 public TransactionAttributeSource transactionAttributeSource() { //@1
  return new AnnotationTransactionAttributeSource();
 }

    //注册bean:事务拦截器
 @Bean
 @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
 public TransactionInterceptor transactionInterceptor(
   TransactionAttributeSource transactionAttributeSource) {
  TransactionInterceptor interceptor = new TransactionInterceptor();
  interceptor.setTransactionAttributeSource(transactionAttributeSource);
        //拦截器中设置事务管理器,txManager可以为空
  if (this.txManager != null) {
   interceptor.setTransactionManager(this.txManager);
  }
  return interceptor;
 }

}

是个配置类,代码比较简单,注册了3个bean,最重要的一点就是添加了事务事务拦截器:TransactionInterceptor。

AutoProxyRegistrar负责启用aop的功能,而ProxyTransactionManagementConfiguration负责在aop中添加事务拦截器,二者结合起来的效果就是:对@Transaction标注的bean创建代理对象,代理对象中通过TransactionInterceptor拦截器来实现事务管理的功能。

再看下代码@1,注册了一个TransactionAttributeSource类型的bean

TransactionAttributeSource接口源码:

public interface TransactionAttributeSource {

 /**
  * 确定给定的类是否是这个TransactionAttributeSource元数据格式中的事务属性的候选类。
  * 如果此方法返回false,则不会遍历给定类上的方法,以进行getTransactionAttribute内省。
  * 因此,返回false是对不受影响的类的优化,而返回true仅仅意味着类需要对给定类上的每个方法进行完全自省。
  **/
 default boolean isCandidateClass(Class<?> targetClass) {
  return true;
 }

 //返回给定方法的事务属性,如果该方法是非事务性的,则返回null。
 TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass);

}

getTransactionAttribute方法用来获取指定方法上的事务属性信息TransactionAttribute,大家对TransactionDefinition比较熟悉吧,用来配置事务属性信息的,而TransactionAttribute继承了TransactionDefinition接口,源码如下,而TransactionAttribute中新定义了2个方法,一个方法用来指定事务管理器bean名称的,一个用来判断给定的异常是否需要回滚事务

public interface TransactionAttribute extends TransactionDefinition {

 //事务管理器的bean名称
 @Nullable
 String getQualifier();

 //判断指定的异常是否需要回滚事务
 boolean rollbackOn(Throwable ex);

}

TransactionAttributeSource接口有个实现类AnnotationTransactionAttributeSource,负责将@Transaction解析为TransactionAttribute对象,大家可以去这个类中设置一下断点看一下@Transaction注解查找的顺序,这样可以深入理解@Transaction放在什么地方才会让事务起效。

AnnotationTransactionAttributeSource内部最会委托给SpringTransactionAnnotationParser#parseTransactionAnnotation方法来解析@Transaction注解,进而得到事务属性配置信息:RuleBasedTransactionAttribute,代码如下:

org.springframework.transaction.annotation.SpringTransactionAnnotationParser

protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
    RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();

    Propagation propagation = attributes.getEnum("propagation");
    rbta.setPropagationBehavior(propagation.value());
    Isolation isolation = attributes.getEnum("isolation");
    rbta.setIsolationLevel(isolation.value());
    rbta.setTimeout(attributes.getNumber("timeout").intValue());
    rbta.setReadOnly(attributes.getBoolean("readOnly"));
    rbta.setQualifier(attributes.getString("value"));
 
    //回滚规则
    List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
    for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
        rollbackRules.add(new RollbackRuleAttribute(rbRule));
    }
    for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
        rollbackRules.add(new RollbackRuleAttribute(rbRule));
    }
    for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
        rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
    }
    for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
        rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
    }
    rbta.setRollbackRules(rollbackRules);

    return rbta;
}

下面来看重点了事务拦截器。

6、TransactionInterceptor

负责拦截@Transaction方法的执行,在方法执行之前开启spring事务,方法执行完毕之后提交或者回滚事务。

在讲这个类的源码之前,先提几个问题,大家带着问题去看代码,理解更深一些。

1、事务管理器是如何获取的?

2、什么情况下事务会提交?

3、什么异常会导致事务回滚?

6.1、invokeWithinTransaction方法

这个方法是事务拦截器的入口,需要spring管理事务的业务方法会被这个方法拦截,大家可以设置断点跟踪一下

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
   final InvocationCallback invocation) throws Throwable {

    TransactionAttributeSource tas = getTransactionAttributeSource();
 //@6-1:获取事务属性配置信息:通过TransactionAttributeSource.getTransactionAttribute解析@Trasaction注解得到事务属性配置信息
    final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
    //@6-2:获取事务管理器
    final TransactionManager tm = determineTransactionManager(txAttr);

    //将事务管理器tx转换为 PlatformTransactionManager
    PlatformTransactionManager ptm = asPlatformTransactionManager(tm);

    if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
        // createTransactionIfNecessary内部,这里就不说了,内部主要就是使用spring事务硬编码的方式开启事务,最终会返回一个TransactionInfo对象
        TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
  // 业务方法返回值
        Object retVal;
        try {
            //调用aop中的下一个拦截器,最终会调用到业务目标方法,获取到目标方法的返回值
            retVal = invocation.proceedWithInvocation();
        }
        catch (Throwable ex) {
            //6-3:异常情况下,如何走?可能只需提交,也可能只需回滚,这个取决于事务的配置
            completeTransactionAfterThrowing(txInfo, ex);
            throw ex;
        }
        finally {
            //清理事务信息
            cleanupTransactionInfo(txInfo);
        }
  //6-4:业务方法返回之后,只需事务提交操作
        commitTransactionAfterReturning(txInfo);
        //返回执行结果
        return retVal;
    }
}

6.2、获取事务管理器

//@6-2:获取事务管理器
final TransactionManager tm = determineTransactionManager(txAttr);

determineTransactionManager源码如下:

org.springframework.transaction.interceptor.TransactionAspectSupport#determineTransactionManager

protected TransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
    // txAttr == null || this.beanFactory == null ,返回拦截器中配置的事务管理器
    if (txAttr == null || this.beanFactory == null) {
        return getTransactionManager();
    }
 
    //qualifier就是@Transactional注解中通过value或者transactionManager来指定事务管理器的bean名称
    String qualifier = txAttr.getQualifier();
    if (StringUtils.hasText(qualifier)) {
        //从spring容器中查找[beanName:qualifier,type:TransactionManager]的bean
        return determineQualifiedTransactionManager(this.beanFactory, qualifier);
    }
    else if (StringUtils.hasText(this.transactionManagerBeanName)) {
        //从spring容器中查找[beanName:this.transactionManagerBeanName,type:TransactionManager]的bean
        return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
    }
    else {
        //最后通过类型TransactionManager在spring容器中找事务管理器
        TransactionManager defaultTransactionManager = getTransactionManager();
        if (defaultTransactionManager == null) {
            defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
            if (defaultTransactionManager == null) {
                defaultTransactionManager = this.beanFactory.getBean(TransactionManager.class);
                this.transactionManagerCache.putIfAbsent(
                    DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
            }
        }
        return defaultTransactionManager;
    }
}

从上面可知,事务管理器的查找顺序:

1、先看@Transactional中是否通过value或者transactionManager指定了事务管理器

2、TransactionInterceptor.transactionManagerBeanName是否有值,如果有,将通过这个值查找事务管理器

3、如果上面2种都没有,将从spring容器中查找TransactionManager类型的事务管理器

6.3、异常情况下,如何走?

try{
    //....
}catch (Throwable ex) {
    //6-3:异常情况下,如何走?可能只需提交,也可能只需回滚,这个取决于事务的配置
    completeTransactionAfterThrowing(txInfo, ex);
    throw ex;
}

源码中可以看出,发生异常了会进入completeTransactionAfterThrowing方法,completeTransactionAfterThrowing 源码如下

protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
        //@6-3-1:判断事务是否需要回滚
        if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
            //通过事务管理器回滚事务
            txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
        }
        else {
            //通过事务管理器提交事务
            txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
        }
    }
}

注意上面的@6-3-1代码,判断事务是否需要回滚,调用的是transactionAttribute.rollbackOn(ex),最终会进入下面这个方法内部

org.springframework.transaction.interceptor.RuleBasedTransactionAttribute#rollbackOn

public boolean rollbackOn(Throwable ex) {
    RollbackRuleAttribute winner = null;
    int deepest = Integer.MAX_VALUE;

    //@Trasaction中可以通过rollbackFor指定需要回滚的异常列表,通过noRollbackFor属性指定不需要回滚的异常
    //根据@Transactional中指定的回滚规则判断ex类型的异常是否需要回滚
    if (this.rollbackRules != null) {
        for (RollbackRuleAttribute rule : this.rollbackRules) {
            int depth = rule.getDepth(ex);
            if (depth >= 0 && depth < deepest) {
                deepest = depth;
                winner = rule;
            }
        }
    }
    //若@Transactional注解中没有匹配到,这走默认的规则,将通过super.rollbackOn来判断
    if (winner == null) {
        return super.rollbackOn(ex);
    }

    return !(winner instanceof NoRollbackRuleAttribute);
}

super.rollbackOn(ex)源码如下,可以看出默认情况下,异常类型是RuntimeException或者Error的情况下,事务才会回滚

@Override
public boolean rollbackOn(Throwable ex) {
    return (ex instanceof RuntimeException || ex instanceof Error);
}

6.4、没有异常如何走?

//6-4:业务方法返回之后,只需事务提交操作
commitTransactionAfterReturning(txInfo);

没有异常的情况下会进入commitTransactionAfterReturning方法,commitTransactionAfterReturning源码如下,比较简单,就是调用事务管理器的commit方法提交事务

protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
        txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
    }
}

源码解析的差不多了,建议大家设置断点跟踪一下,加深对事务原理的理解。

7、重点回顾

1、使用@Transaction的时候,一定别忘记@EnableTransactionManagement注解,否则事务不起效

2、@Transaction的功能主要是通过aop来实现的,关键代码在TransactionInterceptor拦截器中

3、默认情况下,事务只会在 RuntimeException 或 Error 异常下回滚,可以通@Transaction来配置其他需要回滚或不需要回滚的异常类型

8、课堂讨论

下面代码的执行结果是什么?为什么?

@Component
public class ServiceA {

    @Autowired
    ServiceB serviceB;

    @Transactional
    public void m1() {
        try {
            serviceB.m2();
        } catch (Exception e) {
            e.printStackTrace();
        }
        "insert into t_user (name) values ('张三')";
    }
}

@Component
public class ServiceB {

    @Transactional
    public void m2() {
        "insert into t_user (name) values ('李四')";
        throw new RuntimeException("手动抛出异常!");
    }
}
如果你是一名专业的java高级架构师,现在你在面试知识,如下是SpringSpringMVC的面试知识体系结构图 请按照这个体系给出每个知识点的学习理解方便记忆和消化,同时给出每个知识点的高频面试的标准面试答案,结合项目经验给出解释和实战 SpringSpringMVC面试核心知识体系 ├── 一、Spring框架基础 │ ├── 核心概念 │ │ ├── Spring是什么?有哪些核心优势?(解耦、集成、AOP等) │ │ ├── IoC(控制反转)和DI(依赖注入):概念、区别与好处? │ │ └:Spring容器:BeanFactory vs ApplicationContext区别? │ ├── 配置方式 │ │ ├── 有哪几种配置方式?(XML、注解、Java Config) │ │ ├── @Configuration + @Bean 与 @Component 的区别? │ │ └── 如何混合使用不同的配置方式? │ └── Bean管理 │ ├── Bean的作用域:singleton, prototype, request等区别? │ ├── Bean的生命周期:从创建到销毁的完整流程? │ └── 循环依赖问题:什么是循环依赖?Spring如何解决(三级缓存)? ├── 二、IoC(控制反转)与DI(依赖注入)深度解析 │ ├── 依赖注入方式 │ │ ├── 构造器注入 vs Setter注入:推荐哪种?为什么? │ │ ├── 字段注入(@Autowired)的优缺点? │ │ └── @Autowired, @Resource, @Inject 注解的区别? │ ├── 自动装配 │ │ ├── 自动装配的模式(byName, byType等)? │ │ ├── @Primary 和 @Qualifier 注解的作用与区别? │ │ └:如何解决自动装配时的歧义性? │ └── 条件化装配 │ ├── @Profile:作用?如何激活不同环境的配置? │ └── @Conditional:原理?如何自定义条件? ├── 三、AOP(面向切面编程) │ ├── AOP核心概念 │ │ ├── AOP解决了什么问题?主要应用场景?(日志、事务、安全等) │ │ ├── 连接点(Joinpoint)、切点(Pointcut)、通知(Advice)、切面(Aspect)概念? │ │ └── 织入(Weaving):编译期、类加载期、运行期织入区别? │ ├── 代理机制 │ │ ├── Spring AOP默认使用哪种代理?JDK动态代理 vs CGLIB代理区别? │ │ └── 什么情况下使用CGLIB代理? │ └── 通知类型与使用 │ ├── 5种通知类型:@Before, @After, @AfterReturning, @AfterThrowing, @Around │ ├── @Around 和其他通知的区别?如何控制目标方法执行? │ └── 如何获取方法参数、方法名等信息(JoinPoint, ProceedingJoinPoint)? ├── 四、Spring事务管理 │ ├── 事务核心接口 │ │ ├── PlatformTransactionManager:作用?常见实现类(DataSourceTransactionManager等) │ │ ├── TransactionDefinition:定义事务属性(传播行为、隔离级别等) │ │ └── TransactionStatus:描述事务状态 │ ├── 声明式事务 │ │ ├── 如何开启声明式事务?(@EnableTransactionManagement) │ │ ├── @Transactional 注解可以作用在哪些地方?(类、方法)优先级? │ │ └── 事务失效的常见场景?(非public方法、自调用、异常被捕获等) │ └── 事务属性 │ ├── 传播行为(Propagation):REQUIRED, REQUIRES_NEW, NESTED等区别? │ ├── 隔离级别(Isolation):READ_UNCOMMITTED, READ_COMMITTED等与数据库关系? │ └── 回滚规则:如何设置回滚/不回滚的异常类型? ├── 五、Spring MVC核心架构 │ ├── 请求处理流程 │ │ ├── 描述一次请求的完整处理流程(DispatcherServlet -> 控制器 -> 视图)? │ │ ├── 核心组件:DispatcherServlet, HandlerMapping, HandlerAdapter, ViewResolver作用? │ │ └── 流程图的关键步骤是什么? │ ├── 控制器(Controller) │ │ ├── @Controller 和 @RestController 的区别? │ │ ├── 常用注解:@RequestMapping, @GetMapping, @PostMapping等 │ │ └── @ResponseBody 的作用?如何将返回值转为JSON(HttpMessageConverter)? │ └── 数据处理与视图解析 │ ├── 参数绑定:@RequestParam, @PathVariable, @RequestBody, @ModelAttribute区别? │ ├── 数据模型:Model, ModelMap, ModelAndView 的使用? │ └── 视图解析:InternalResourceViewResolver如何工作? ├── 六、Spring MVC高级特性 │ ├── 拦截器(Interceptor) │ │ ├── 拦截器 vs 过滤器(Filter)的区别? │ │ ├── 拦截器的三个方法:preHandle, postHandle, afterCompletion执行时机? │ │ └── 如何配置多个拦截器?执行顺序? │ ├── 统一异常处理 │ │ ├── @ControllerAdvice + @ExceptionHandler 如何实现全局异常处理? │ │ ├── HandlerExceptionResolver 接口的作用? │ │ └── @ResponseStatus 注解的使用? │ └── 文件上传与Restful API │ ├── 如何实现文件上传?(MultipartResolver) │ ├── Restful风格API的设计原则?(GET/POST/PUT/DELETE) │ └── 如何解决跨域问题?(@CrossOrigin, CorsFilter) ├── 七、Spring与第三方框架集成 │ ├── 数据访问 │ │ ├── Spring JDBC:JdbcTemplate的优势? │ │ ├── 集成MyBatis:需要哪些配置?@MapperScan作用? │ │ └── 集成JPA(Hibernate):如何配置? │ ├── 测试框架 │ │ ├── Spring TestContext Framework:@SpringBootTest, @DataJpaTest等 │ │ ├── 如何模拟MVC测试?(@WebMvcTest, MockMvc) │ │ └── 如何 mock Bean?(@MockBean) │ └── 其他集成 │ ├── 如何集成缓存?(@Cacheable, 支持Redis, Ehcache等) │ └── 如何集成任务调度?(@Scheduled, @Async) ├── 八、Spring新特性与原理进阶 │ ├── Spring Boot关联 │ │ ├── Spring Boot 和 Spring 的关系?自动配置原理? │ │ └── starter 的作用?如何自定义 starter? │ ├── 设计模式应用 │ │ ├── Spring中使用了哪些设计模式?(工厂、单例、代理、模板方法等) │ │ └── 举例说明模板方法模式在JdbcTemplate中的应用? │ └── 源码与原理 │ ├── Spring如何管理单例Bean的线程安全问题? │ ├── ApplicationContext的刷新流程(refresh()方法)大致过程? │ └── Spring事件机制(ApplicationEvent、ApplicationListener)? └── 九、常见问题与解决方案 ├── 性能与配置 │ ├── 如何优化Spring应用启动速度?(懒加载、组件扫描路径优化) │ └── 如何外部化配置?(@PropertySource, @Value, @ConfigurationProperties) ├── 开发实践 │ ├── 如何优雅地读取配置文件? │ ├── Spring中有哪些扩展点?(BeanPostProcessor, BeanFactoryPostProcessor) │ └── 如何自定义注解并使其生效? └── 疑难杂症 ├── @Transactional 和 @Async 在同一个类中调用为什么失效?(代理机制) └── 如何解决Spring应用中的内存泄漏问题?
最新发布
09-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值