回炉Spring-AOP及事务源码解读

一、AOP

  AOP,面向切面编程

  即拓展功能不通过修改源代码来实现。

  采用横向抽取机制,取代了传统的纵向继承体系的重复性代码。在运行期间通过代理方式向目标类中织入增强代码。

  

 

实现一个AOP的步骤:

  1、将需要增强的目标类和切面类都注入到Spring容器中,标注使Spring知道哪个是切面类,@Aspect(曾犯错,在切面类上没有标注@Component注解)

  2、使用@Pointcut注解定义切点。切点分为execution方式和annotation方式

    ①:annotation方式

      @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")

    ②:execution方式

      @Pointcut("execution(* com.mutest.controller..*.*(..))")

        第一个 * 号的位置:表示返回值类型,* 表示所有类型

        包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,在本例中指 com.mutest.controller包、子包下所有类的方法

        第二个 * 号的位置:表示类名,* 表示所有类

        *(..):这个星号表示方法名,* 表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数

      

  3、在切面类上的通知方法上标注通知注解(如@Around,@Before等),并在注解中指明切入点表达式(或切点方法)

  4、开启基于注解的aop模式,在配置类上加上注解@EnableAspectJAutoProxy

    注:(SpringBoot默认开启了基于注解的AOP模式,不用再启动类上再加@EnableAspectJAutoProxy)

    

 

@AfterReturning注解的returning可将增强方法的返回值映射到参数上

    @AfterReturning(value = "pointCut()", returning = "result")
    public void afterReturning(Object result) throws Throwable {}

@AfterThrowing(value="pointCut()",throwing="exception")的throwing将增强方法的异常信息映射到参数上

获取切入点方法名:joinPoint.getSignature().getName() 

获取方法入参:joinPoint.getArgs()

    @Before("pointCut()")
    // 方法若有多个参数,JoinPoint一定要放在第一位
    public void before(JoinPoint joinPoint) {
        String name = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
    }

 

 

AOP原理:

  @EnableAspectJAutoProxy注解做了什么?

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {...}

  @EnableAspectJAutoProxy往容器中导入了AspectJAutoProxyRegistrar,利用AspectJAutoProxyRegistrar自定义往容器中注册了name为org.springframework.aop.config.internalAutoProxyCreator,class为AnnotationAwareAspectJAutoProxyCreator的bean。

  也就是说,@EnableAspectJAutoProxy往Spring容器中注册了AnnotationAwareAspectJAutoProxyCreator这个bean。

 

  技巧:如果看到了Enable开头的注解,就看这个注解有没有往容器中注册一些组件,如果注册组件了,这些组件的功能是什么,如果具体功能搞明白了,那么这个注解的原理就清楚了。

  那么既然@EnableAspectJAutoProxy往Spring容器中注册了AnnotationAwareAspectJAutoProxyCreator这个bean(从名字看是:注解装配切面代理创造器),那就看一下这个bean的功能是什么,源码走起:

  AnnotationAwareAspectJAutoProxyCreator 的继承关系如下:

  

 

看到其祖先类实现了InstantiationAwareBeanPostProcessor 接口,而此接口又实现了BeanPostProcessor接口,而这个接口我们知道叫做后置处理器,后置处理器的功能就是在bean初始化的前后做一些工作。

抽象父类AbstractAutoProxyCreator 又实现了BeanFactoryAware,可以往代码中注入BeanFactory。

那么先重点看与setBeanFactory以及与后置处理器相关的逻辑,通过源码发现AbstractAutoProxyCreator有setBeanFactory()以及后置处理器相关的逻辑。而在AbstractAutoProxyCreator的子抽象类AbstractAdvisorAutoProxyCreator又重写了setBeanFactory()方法

public void setBeanFactory(BeanFactory beanFactory) {
    super.setBeanFactory(beanFactory);
    if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
        throw new IllegalArgumentException("AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
    } else {
        this.initBeanFactory((ConfigurableListableBeanFactory)beanFactory);
    }
}

 

由于其子类AnnotationAwareAspectJAutoProxyCreator 重写了initBeanFactory方法,所以最终调用的是AnnotationAwareAspectJAutoProxyCreator 中的initBeanFactory方法中的逻辑:

protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        super.initBeanFactory(beanFactory);
        if (this.aspectJAdvisorFactory == null) {
            this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
        }

        this.aspectJAdvisorsBuilder = new AnnotationAwareAspectJAutoProxyCreator.BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
    }

 

 

断点看AOP的整个执行流程:

1、new AnnotationConfigApplicationContext(AopConfig.class); 创建Spring容器,接下来看其构造器逻辑

2、先注册配置类,然后调用refresh()方法刷新容器,接下来看refresh()的逻辑

3、invokeBeanFactoryPostProcessors(beanFactory);实例化并调用所有注册的BeanFactoryPostProcessor

4、registerBeanPostProcessors(beanFactory); 注册bean的后置处理器来拦截bean的创建

  1):先获取ioc容器中已经定义了的所有实现BeanPostProcessor接口的后置处理器的name.  String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

  2):给容器中添加了额外的BeanPostProcessor  beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

  3):遍历所有的BeanPostProcessor,按照实现了PriorityOrdered接口的,和实现了Ordered接口的进行分组,分别保存在不同的List集合中

      ①:若实现了PriorityOrdered,则先创建其对象,当成普通bean注册到Spring容器中,然后将其放进priorityOrderedPostProcessors集合,若其又实现了MergedBeanDefinitionPostProcessor,将其再放进internalPostProcessors集合;

      ②:若其实现了Ordered接口,将其bean name放入orderedPostProcessorNames集合;

      ③:若两个接口都没实现,则将其bean name放进nonOrderedPostProcessorNames集合;

  4):优先注册实现了PriorityOrdered接口的BeanPostProcessor作为bean的后置处理器到Spring容器中,再注册实现了Ordered接口的BeanPostProcessor,最后注册其他的BeanPostProcessor.

     注册的BeanPostProcessor保存在AbstractBeanFactory的 private final List<BeanPostProcessor> beanPostProcessors = new BeanPostProcessorCacheAwareList();集合属性中

  5):注册其实就是步骤3)中的根据其name获取BeanPostProcessor对象{BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);},实际上就是创建BeanPostProcessor对象然后将其保存在Spring容器中。

      以创建name为internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】为例,看一下创建过程:

    (1):创建bean的实例,getBean()——doGetBean()——getSingleton()——getObject()——createBean()——doCreateBean()

    (2):populateBean:给bean的各种属性赋值

    (3):initializeBean:初始化bean

       ①:invokeAwareMethods()判断bean是不是实现了xxxAware接口,如果实现了就调用相关的setXxx方法给bean的属性赋值

       ②:Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);应用bean的后置处理器的初始化前置方法,获取所有的后置处理器(之前注册保存在AbstractBeanFactoryList<BeanPostProcessor>属性中),遍历调用它们的postProcessBeforeInitialization()方法

       ③:invokeInitMethods(beanName, wrappedBean, mbd); 执行初始化方法,先@PostConstruct() 注解方法,然后如果实现了InitializingBean,执行afterPropertiesSet,再执行自定义的初始化方法(如果在@Bean注解指定了initMethod的话)

       ④:Object wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);应用bean的后置处理器的初始化后置方法,获取所有的后置处理器,遍历调用其postProcessAfterInitialization()方法

  6):由于AnnotationAwareAspectJAutoProxyCreator实现了 BeanFactoryAware接口,所以在invokeAwareMethods()方法中,回到了上面说的调用其抽象父类AbstractAdvisorAutoProxyCreator重写的setBeanFactory()方法。然后走到了AnnotationAwareAspectJAutoProxyCreator 的initBeanFactory()方法,至此,BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功

  7):最后将所有的BeanPostProcessor注册到BeanFactory

    registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

    -->beanFactory.addBeanPostProcessor(postProcessor);

    注册的BeanPostProcessor保存在AbstractBeanFactoryprivate final List<BeanPostProcessor> beanPostProcessors = new BeanPostProcessorCacheAwareList();集合属性中

 

  以上就是创建和注册AnnotationAwareAspectJAutoProxyCreator的过程。

 

  接下来看其作为一个BeanPostProcessor如何影响bean的创建过程的:

5、finishBeanFactoryInitialization(beanFactory);完成BeanFactory初始化工作,创建剩下的单实例bean,为什么说是剩下的呢?因为BeanPostProcessors类型的bean在步骤4已经创建

  完成了

  1):preInstantiateSingletons()-->遍历获取容器中所有的beanDefinitionNames,遍历依此创建对象getBean(beanName); 在DefaultListableBeanFactory类中

  2):getBean(beanName)-->doGetBean()-->getSingleton(beanName) ,在创建bean之前先尝试获取单实例Bean的实例,为什么呢?因为只要创建好的bean就会被缓存起来

    ①:先去JVM缓存 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);  /** Cache of singleton objects: bean name to bean instance. */ 中去获取缓存的创建好了的单实例bean对象

    ②:若创建完成的单实例bean缓存中没有,再去当前创建bean池中去尝试获取。

      当前创建bean池:private final Set<String> singletonsCurrentlyInCreation =Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(16)); // 池中保存中的是 bean name

      因为在创建单实例bean的时候会存在依赖注入的情况,为了避免循环依赖,Spring在创建bean的过程中,若发现有依赖bean,则尝试去创建依赖的bean,因此Spring将每一个正在创建的bean的beanName放在一个“当前创建bean池”中,bean在创建过程中,BeanName将一直存在这个池中。

    ③:如果当前线程创建bean池有,则尝试从提前创建单例bean缓存中加载bean:private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16); /** Cache of early singleton objects: bean name --> bean instance */

    ④:如果earlySingletonObjects 缓存中加载不成功,则再次尝试从singletonFactories中获取提前曝光的ObjectFactory,private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); /** Cache of singleton factories: bean name --> ObjectFactory */

      如果根据beanName找到了ObjectFactory,则从ObjectFactory中获取bean实例,然后将其放在earlySingletonObjects 缓存中,再将其ObjectFactory从singletonFactories中移除。

      因为Spring为了避免循环依赖,在Spring中创建bean的原则是不等bean创建完就会将创建bean的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创建时候需要依赖上一个bean则直接使用ObjectFactory去获取依赖bean的实例。

      

  3):createBean()  创建bean实例

    ①:Object bean=resolveBeforeInstantiation(beanName, mbdToUse); 参数:RootBeanDefinition mbdToUse,bean的定义信息。

       方法的作用是:给BeanPostProcessor一个机会返回一个代理对象就不用创建其对象了。如果可以,直接返回代理对象,如果不能,则继续执行doCreateBean(beanName, mbdToUse, args);,其实现为:

            bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                    if (bean != null) {
                        bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                    }

      这个方法的逻辑是:先拿到所有的后置处理器然后遍历,如果其中一个后置处理器实现了InstantiationAwareBeanPostProcessor接口,则执行这个后置处理器的postProcessBeforeInstantiation方法,如果返回了bean对象,则执行applyBeanPostProcessorsAfterInitialization并返回bean实例,结束bean的创建,不走下面的doCreateBean

   

    注意:InstantiationAwareBeanPostProcessor虽继承了BeanPostProcessor,但其定义了postProcessBeforeInstantiation和postProcessAfterInstantiation方法,与BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法不同,BeanPostProcessor的两个方法是在bean实例创建完成之后的初始化前后调用的,而InstantiationAwareBeanPostProcessor的两个方法是在创建bean实例之前尝试返回代理对象的。

    这也是AnnotationAwareAspectJAutoProxyCreator的功能,在所有的bean创建之前会有一个拦截,尝试返回其代理对象

    ②:doCreateBean,真正的创建bean的实例,即上面4.5的流程

 

 

AnnotationAwareAspectJAutoProxyCreator做了什么事情?

一下逻辑都在create()方法中

1、每一个bean创建之前,都会调用postProcessBeforeInstantiation(); 代码在AbstractAutoProxyCreator#postProcessBeforeInstantiation

  其处理逻辑是:

  1):判断当前bean是否在advisedBean(保存了所有增强过的bean的缓存)中,private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);

  2):isInfrastructureClass(beanClass):判断当前bean是否是 基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean或者是否是切面(是否有@Aspect注解)

  3):或者shouldSkip(beanClass, beanName):是否需要跳过

      ①:获取候选的增强器(切面里面的增强方法)List<Advisor> candidateAdvisors = findCandidateAdvisors();

      ②:遍历然后判断每一个增强器是否是AspectJPointcutAdvisor类型的,如果是,返回true,否则返回flase

      ③:而我们的增强器类型是:InstantiationModelAwarePointcutAdvisor,因此,shouldSkip方法永远返回false

2、执行doCreateBean方法,创建bean,并初始化

3、postProcessAfterInstantiationpostProcessBeforeInitialization一个返回true,一个返回bean对象本身,什么都没做

4、postProcessAfterInitialization方法:创建完对象并初始化后,调用它。代码在AbstractAutoProxyCreator#postProcessAfterInitialization  其逻辑是:

  判断当前bean是否已经代理过,若没有则执行:return wrapIfNecessary(bean, beanName, cacheKey); 这个方法的作用是,封装bean如果必要的话,也就是在这里创建目标类的代理对象

  1):Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);找到所有能应用到当前bean的增强方法

    (1):获取配置的所有的切面增强方法

    (2):找到所有的增强方法中能应用到当前bean方法中的

    (3):获取到能在当前bean使用的增强方法的集合,并按照一定规则排序

    (4):如果能在当前bean使用的增强方法的集合不为空,则转为数组返回,否则返回null

  2):如果返回的数组不为空,则需要代理

    (1):将bean的name作为key,值为true,放在advisedBeans(所有增强过的bean的ConcurrentHashMap)中

    (2):创建代理对象,Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

      ①:如果能在当前bean使用的增强方法

      ②:遍历将其添加到proxyFactory中

      ③: DefaultAopProxyFactory中创建代理对象,如果目标类实现了接口,则使用JDK动态代理;否则使用CGlib动态代理

         JdkDynamicAopProxy(AdvisedSupport config)

         ObjenesisCglibAopProxy(AdvisedSupport config)

    (3):将bean作为key,代理对象的class对象作为value,保存到private final Map<Object, Class<?>> proxyTypes = new ConcurrentHashMap<Object, Class<?>>(16);

    (4):返回代理对象(代理对象中包含了增强器和目标对象等)

    (5):以后在容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行增强方法的流程

  3)否则不需要代理,将bean的name作为key,值为false,放在advisedBeans中,表示不需要增强

 

 总结:AnnotationAwareAspectJAutoProxyCreator在初始化后置方法postProcessAfterInitialization中,判断是否有增强方法能应用到当前bean中,若有,则为当前bean创建代理对象,并保存到Spring容器中,以后从Spring容器中获取到的就是代理对象。

   

 

从容器中获取的对象是代理对象,即容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细的信息(比如要应用的切面中的增强方法,也叫增强器,目标对象等)

执行目标对象Target中的切入点方法,即执行被增强的方法的流程:

F7进入切点方法:

1、CglibAopProxy.intercept();  拦截目标方法的执行

2、获取目标对象

  Object target = null; // 目标对象
  TargetSource targetSource = this.advised.getTargetSource();

  target = targetSource.getTarget();

3、根据ProxyFactory对象获取将要执行的目标方法拦截器链

    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

    DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice  // 实际逻辑代码

    1):List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);  

        保存所有的拦截器,包括一个默认的 ExposeInvocationInterceptor.ADVISOR 和 其他所有切点方法的增强器

    2):遍历所有的增强器,将其转为MethodInterceptor  【MethodInterceptor[] interceptors = registry.getInterceptors(advisor);】

                        如果增强器是MethodInterceptor,直接放入List<MethodInterceptor>集合中

         如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor,然后再放入List<MethodInterceptor>集合中

         最后将集合转为数组返回

4、如果没有拦截器链,则直接执行目标方法(拦截器链,每一个通知方法又被包装为方法拦截器,利用MethodInterceptor机制)

5、如果有拦截器链,把需要执行的目标对象,目标方法,拦截器等信息作为参数创建一个CglibMethodInvocation对象并调用其proceed()方法

  retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); 

  CglibMethodInvocation对象:

  

  拦截器列表:

  

6、拦截器的触发过程

  1):如果没有拦截器执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(即执行到了最后一个拦截器),则执行目标方法

  2):链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回后再去执行(类似于递归调用),

    如上面拦截器的调用顺序是 Expose-->AfterReturning-->Around-->Before,然后前面的等待后面的返回再执行,最后实际执行顺序是Before-->Around-->AfterReturning-->Expose

    拦截器链的机制,保证通知方法与目标方法的执行顺序。

  

AOP总结

  1、@EnableAspectJAutoProxy  开启AOP功能

  2、@EnableAspectJAutoProxy  会给容器中注册一个组件 AnnotationAwareApectJAutoProxyCreator

  3、AnnotationAwareApectJAutoProxyCreator是一个后置处理器

  4、容器的创建流程

    1):registerBeanPostProcessors(beanFactory);  注册后置处理器,创建AnnotationAwareApectJAutoProxyCreator对象

    2):finishBeanFactoryInitialization(beanFactory);  初始化剩下的单实例bean

      (1):创建业务逻辑组件和切面组件

      (2):AnnotationAwareApectJAutoProxyCreator  拦截组件的创建过程

      (3): 组件创建完成之后,作为后置处理器的AnnotationAwareApectJAutoProxyCreatorpostProcessAfterInitialization方法中判断组件是否需要增强,如果需要则 将需要应用到目标对象的切面中的通知方法,包装成增强器Advisor,然后给业务逻辑组件创建一个代理对象。

  5、执行目标方法

    1):代理对象来执行目标方法

    2):CglibAopProxy.intercept();  拦截目标方法的执行

      (1):得到目标方法执行的拦截器链

      (2):利用拦截器的链式机制,依次进入每一个拦截器进行执行

      (3):实际执行顺序:

          正常执行:前置通知-->目标方法-->后置通知-->返回通知

          出现异常:前置通知-->目标方法-->后置通知-->异常通知

 

 

 

 

二、事务

  声明式事务

  jdbc和tx依赖:

        <!--jdbc & tx-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

  数据源和mysql连接依赖:

     <!--dbcp datasource-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-dbcp2</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

 

  配置文件信息:

/**
 * @EnableTransactionManagement 开启基于注解的事务管理功能
 * 1、配置数据源
 * 2、配置事务管理器来管理事务
 * 3、给方法上标注 @Transactional 表示当前方法是一个事务方法,@Transaction默认回滚Error和RuntimeException,但是不包括和RuntimeException
 * 一样同属于Exception子类的如IOException、SQLException和自定义异常等,对于这些异常如果也要回滚要在rollbackFor中指定
 */
@EnableTransactionManagement
@Configuration
@ComponentScan(value = {"com.yang.service"})
public class TransactionConfig {

    @Bean
    public DataSource myDataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUsername("yang");
        dataSource.setPassword("yang");
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        return dataSource;
    }

    /**
     * 如果bean之间有依赖,直接放进参数中即可,参数值会从Spring容器中取,然后赋值
     * 参数从Spring容器中取
     *
     * @param myDataSource
     * @return
     */
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource myDataSource) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(myDataSource);
        // 也可以直接调用,Spring对@Configuration类会特殊处理;给容器中加组件的方法,多次调用都只是从容器中找组件
        //        JdbcTemplate jdbcTemplate = new JdbcTemplate(myDataSource());
        return jdbcTemplate;
    }

    /**
     * 注册事务管理器在容器中
     *
     * @return
     * @throws Exception
     */
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(myDataSource());
    }
}

 

@EnableTransactionManagement 做了什么?

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

    boolean proxyTargetClass() default false;

    AdviceMode mode() default AdviceMode.PROXY;

    int order() default Ordered.LOWEST_PRECEDENCE;
}

1、导入了TransactionManagementConfigurationSelector,TransactionManagementConfigurationSelector往容器中导入了两个组件

  AutoProxyRegistrar 、ProxyTransactionManagementConfiguration

/**
     * Returns {@link ProxyTransactionManagementConfiguration} or
     * {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY}
     * and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()},
     * respectively.
     */
    @Override
    protected String[] selectImports(AdviceMode adviceMode) {
        switch (adviceMode) {
            case PROXY:
                return new String[] {AutoProxyRegistrar.class.getName(),
                        ProxyTransactionManagementConfiguration.class.getName()};
            case ASPECTJ:
                return new String[] {determineTransactionAspectClass()};
            default:
                return null;
        }
    }

    private String determineTransactionAspectClass() {
        return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
                TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
                TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
    }

//     public static final String JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME =
            "org.springframework.transaction.aspectj.AspectJJtaTransactionManagementConfiguration";

//     public static final String TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME =
            "org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration";

(1)、AutoProxyRegistrar

  给容器中注册了一个beanNameorg.springframework.aop.config.internalAutoProxyCreator,类型为InfrastructureAdvisorAutoProxyCreator的组件(bean),其是一个后置处理器,和AOP中的AnnotationAwareAspectJAutoProxyCreator类似,它们beanName相同。都是在对象创建完成之后利用后置处理器的初始化后置方法,包装对象,然后返回一个包含增强器的代理对象,代理对象执行方法利用拦截器链进行调用。

 

 (2)、ProxyTransactionManagementConfiguration是一个配置文件类

/**
 * {@code @Configuration} class that registers the Spring infrastructure beans
 * necessary to enable proxy-based annotation-driven transaction management.
 *
 * @author Chris Beams
 * @since 3.1
 * @see EnableTransactionManagement
 * @see TransactionManagementConfigurationSelector
 */
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

    @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() { // 事务增强器
        BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
        advisor.setTransactionAttributeSource(transactionAttributeSource());
        advisor.setAdvice(transactionInterceptor());
        if (this.enableTx != null) {
            advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
        }
        return advisor;
    }

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionAttributeSource transactionAttributeSource() {
        return new AnnotationTransactionAttributeSource();
    }

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionInterceptor transactionInterceptor() { // 事务拦截器
        TransactionInterceptor interceptor = new TransactionInterceptor();
        interceptor.setTransactionAttributeSource(transactionAttributeSource());
        if (this.txManager != null) {
            interceptor.setTransactionManager(this.txManager);
        }
        return interceptor;
    }

}

 

  1、往容器中注册事务增强器transactionAdvisor,其中事务增强器中又依赖了:

    1):事务增强器要用事务注解的参数信息,TransactionAttributeSource,AnnotationTransactionAttributeSource来解析事务注解

    2):事务拦截器:TransactionInterceptor,保存了事务属性信息,事务管理器。其实现了MethodInterceptor接口。在目标方法执行的时候:执行拦截器链,然后执行事务拦截器:

      (1):先获取事务相关的属性

      (2):再获取PlatformTransactionManager事务管理器,如果在@Transactional注解中没有指定transactionManager,则最终会从容器中按照类型获取一个PlatformTransactionManager

      (3):执行目标方法

         如果异常,获取到事务管理器,利用事务管理回滚操作

         【transactionInfo.getTransactionManager().rollback(txInfo.getTransactionStatus())】

           如果正常,利用事务管理器,提交事务【transactionInfo.getTransactionManager().commit(txInfo.getTransactionStatus());】

 

    TransactionInterceptor#invoke

    @Override
    @Nullable
    public Object invoke(MethodInvocation invocation) throws Throwable {
        // Work out the target class: may be {@code null}.
        // The TransactionAttributeSource should be passed the target class
        // as well as the method, which may be from an interface.
        Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

        // Adapt to TransactionAspectSupport's invokeWithinTransaction...
        return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
    }

    

    @Transactional注解处理器的核心代码,TransactionAspectSupport#invokeWithinTransaction:278,从TransactionInterceptor#invoke进入:

 /**
     * General delegate for around-advice-based subclasses, delegating to several other template
     * methods on this class. Able to handle {@link CallbackPreferringPlatformTransactionManager}
     * as well as regular {@link PlatformTransactionManager} implementations.
     * @param method the Method being invoked
     * @param targetClass the target class that we're invoking the method on
     * @param invocation the callback to use for proceeding with the target invocation
     * @return the return value of the method, if any
     * @throws Throwable propagated from the target invocation
     */
    @Nullable
    protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
            final InvocationCallback invocation) throws Throwable {

        // If the transaction attribute is null, the method is non-transactional.
        TransactionAttributeSource tas = getTransactionAttributeSource();
        final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
        final PlatformTransactionManager tm = determineTransactionManager(txAttr); // 确定要用于给定交易的特定交易管理器
        final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

        if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
            // Standard transaction demarcation with getTransaction and commit/rollback calls.
            TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); // 开启事务
            Object retVal = null;
            try {
                // This is an around advice: Invoke the next interceptor in the chain.
                // This will normally result in a target object being invoked.
                retVal = invocation.proceedWithInvocation(); // 执行业务方法
            }
            catch (Throwable ex) {
                // target invocation exception
                completeTransactionAfterThrowing(txInfo, ex); // 回滚事务
                throw ex; // 仍往上抛出异常,供上层捕获
            }
            finally {
                cleanupTransactionInfo(txInfo); // Reset the TransactionInfo ThreadLocal.
            }
            commitTransactionAfterReturning(txInfo); // 提交事务
            return retVal;
        }

        else {
            ...
        }
    }

  

  回滚事务:

  /**
     * Handle a throwable, completing the transaction.
     * We may commit or roll back, depending on the configuration.
     * @param txInfo information about the current transaction
     * @param ex throwable encountered
     */
    protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
        if (txInfo != null && txInfo.getTransactionStatus() != null) {
            if (logger.isTraceEnabled()) {
                logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
                        "] after exception: " + ex);
            }
            if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
                try {
                    txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
                }
                catch (TransactionSystemException ex2) {
                    logger.error("Application exception overridden by rollback exception", ex);
                    ex2.initApplicationException(ex);
                    throw ex2;
                }
                catch (RuntimeException | Error ex2) {
                    logger.error("Application exception overridden by rollback exception", ex);
                    throw ex2;
                }
            }
            else {
                // We don't roll back on this exception.
                // Will still roll back if TransactionStatus.isRollbackOnly() is true.
                // 默认回滚(ex instanceof RuntimeException || ex instanceof Error) 异常,其他异常不会回滚,仍提交事务
                try {
                    txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
                }
                catch (TransactionSystemException ex2) {
                    logger.error("Application exception overridden by commit exception", ex);
                    ex2.initApplicationException(ex);
                    throw ex2;
                }
                catch (RuntimeException | Error ex2) {
                    logger.error("Application exception overridden by commit exception", ex);
                    throw ex2;
                }
            }
        }
    }

    最终回滚代码为:DataSourceTransactionManager#doRollback

DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
con.rollback();

 

  提交事务:

  /**
     * Execute after successful completion of call, but not after an exception was handled.
     * Do nothing if we didn't create a transaction.
     * @param txInfo information about the current transaction
     */
    protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
        if (txInfo != null && txInfo.getTransactionStatus() != null) {
            if (logger.isTraceEnabled()) {
                logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
            }
            txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); // 提交事务
        }
    }

   最终提交代码为:

DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
con.commit();

 

 

END.

posted @ 2021-04-09 21:39  杨岂  阅读(336)  评论(0编辑  收藏  举报