zoukankan      html  css  js  c++  java
  • spring事务源码分析

      Spring事务是基于Aop,具体而言是通过一个TransactionInterceptor的拦截器来实现。下面整理一下Spring实现事务操作的具体流程,以便于以后复习。

    一.注解EnableTransactionManagement

      使用EnableTransactionManagement注解可以开启Spring事务,而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.class的功能
    2. Spring事务默认是使用Proxy代理模式

    二. TransactionManagementConfigurationSelector

      该类实现了ImportSelector接口,通过覆写selectImports()方法,手动将java类注册到Spring框架的IOC容器中

    @Override
        protected String[] selectImports(AdviceMode adviceMode) {
            switch (adviceMode) {
                case PROXY:  // 默认就是Proxy模式
                    return new String[] {AutoProxyRegistrar.class.getName(),ProxyTransactionManagementConfiguration.class.getName()};
                case ASPECTJ:
                    return new String[] {determineTransactionAspectClass()};
                default:
                    return null;
            }
        }

       通过上述源代码可知,Spring默认将AutoProxyRegistrar.class和ProxyTransactionManagementConfiguration.class注入到IOC容器。

      接下来,应该是看看这两个类到底干了什么事?

    三. AutoProxyRegistrar

      跟踪源代码可知,Spring会将InfrastructureAdvisorAutoProxyCreator.class注入到IOC容器,然后请看该类类图:

       由图知InfrastructureAdvisorAutoProxyCreator.class是一个BeanPostProcessor.class的子类,理论上它可以在Spring初始化bean之前或之后进行功能增强,Sping框架原生选择是之后增强,具体的增强方法是在AbstractAutoProxyCreator#postProcessAfterInitialization()方法。


      接下来请看看postProcessAfterInitialization()方法源码:
        @Override
        public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
            if (bean != null) {
                Object cacheKey = getCacheKey(bean.getClass(), beanName);
                if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                    return wrapIfNecessary(bean, beanName, cacheKey);
                }
            }
            return bean;
        }
     /**  Wrap the given bean if necessary  
      *  对bean进行包装,其实就是创建代理对象
      */
    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
            
            // 省略。。。。
            // Create proxy if we have advice.
            Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
            if (specificInterceptors != DO_NOT_PROXY) {
                this.advisedBeans.put(cacheKey, Boolean.TRUE);
                // 创建代理,jdk动态代理或者cglib代理
                Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
                this.proxyTypes.put(cacheKey, proxy.getClass());
                return proxy;
            }
    
        }   

      上述代码的作用就是,Spring在bean初始化之后,会判断该bean是否需要创建一个代理对象,如果需要,就会使用jdk动态代理或者cglib创建一个代理类(这一块不是本篇文章分析的重点)。

      到此,AutoProxyRegistrar.class类的功能就分析完毕。

    四. ProxyTransactionManagementConfiguration

      该类主要是在IOC容器中注入事务拦截器TransactionInterceptor.class和Spring的事务注册解析器,具体源码如下:

    @Configuration  
    public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
            /**
             *  事务注册解析器 
             */
        @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;
        }
    
    }

      继续跟踪源码,咱们会发现AnnotationTransactionAttributeSource.class的底层调用了SpringTransactionAnnotationParser.class,由类名就可知道这个类的作用。事实上它也确实是解析@Transactional,具体可以参看该类源码,很简单的。

      查看类图可知TransactionInterceptor.class是Advice的一个实现,而且是MethodInterceptor接口的一个实现,这说明它跟Spring Aop中前置、后置通知一样,事实上它就是一个环绕通知(around advice),完全遵守底层的责任链调用模式。

    五. 事务调用链

      为了便于理解,先创建一个测试demo

    • DAO层
    @Repository
    public class UserDao {
        @Autowired
        private JdbcTemplate jdbcTemplate;
        public void  addUser() {
            jdbcTemplate.update("INSERT t_user(userName,age) VALUES ('test',100);");
        }
    }
    • Service层
    public interface UserService {
        public void addUser();
    }
    @Service
    public class UserServiceImpl  implements UserService {
    
        @Autowired
        private UserDao userDao;
    
        @Override
        @Transactional
        public void addUser() {
            userDao.addUser();
    //        int i = 1 / 0;
        }
    }
    • 配置类
    @Configuration
    @ComponentScan("qinfeng.zheng.spring01.v6")
    @EnableTransactionManagement  // 开启事务
    public class SpringConfig {
    
        @Bean
        public DataSource dataSource() {
            MysqlDataSource dataSource = new MysqlDataSource();
            dataSource.setUser("root");
            dataSource.setPassword("xxxxxxx");
            dataSource.setURL("jdbc:mysql://xxx.xxx.xx.xx:3306/tb_user?useUnicode=true&characterEncoding=UTF-8");
    //        dataSource.setDatabaseName("tb_user");
            return dataSource;
        }
    
        @Bean
        public JdbcTemplate jdbcTemplate() {
            return new JdbcTemplate(dataSource());
        }
    
        @Bean
        public PlatformTransactionManager txManager() {
            return new DataSourceTransactionManager(dataSource());
        }
    }
    • 启动类
    public class App {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
            UserService orderService = context.getBean(UserService.class);
            orderService.addUser();
        }
    }

      直接在启动类上的orderService.addUser();这一行代码上戳个断点,然后debug走起来。。。

      由上图知orderService其实是一个JdkDynamicAopProxy的代理对象,然后咱们F7,会进入到JdkDynamicAopProxy#invoke()方法。

    @Override
    @Nullable
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // ....
            // 获取当前方法的拦截器链
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                
            if (chain.isEmpty()) {  // 如果拦截链为空
                //.....
            }
            else {  
                // 创建一个MethodInvocation对象,其实就是对proxy, target, method, args, targetClass, chain这些参数的封装
                MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // 调用拦截器链
                retVal = invocation.proceed();
            }
    
            //......
            return retVal;
        }
         //.....
    }

      通过debug可知,chain链中有且只有一个 元素,而且这个元素就是前面注册的TransactionInterceptor.class, 还记得这个类吗?Spring的事务全靠它呢!

      继续debug....

      通过debug很容易发现invocation对象的真实类型是ReflectiveMethodInvocation.class, 这个类在分析Spring Aop的调用链时超级重要。因为本篇主要讲Spring事务,所以咱们直接进入该类的proceed()方法。

    @Override
    @Nullable
    public Object proceed() throws Throwable {
        // 调用真实业务方法,底层也是通过反射
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }
    
        Object interceptorOrInterceptionAdvice = his.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            
        }else {
            // this很重要,这里会递归调用proceed()
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

      因为interceptorOrInterceptionAdvice的真实类型是TransactionInterceptor.class,所以debug进入TransactionInterceptor#invoke()。

    public Object invoke(MethodInvocation invocation) throws Throwable {
        //真实目标类
        Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
    
        //重点分析该方法
        return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
    }
    @Nullable
    protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation) throws Throwable {
        if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
            // 开启事务,底层会启用jdbc开启事务,
            TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
            // 目标方法返回值
            Object retVal;
            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) {
                // 如果目标方法抛出异常,这里会回滚事务
                completeTransactionAfterThrowing(txInfo, ex);
                throw ex;
            }
            finally {
                // 清埋事务
                cleanupTransactionInfo(txInfo);
            }
            // commit事务
            commitTransactionAfterReturning(txInfo);
            return retVal;
        }else{
            //.....
        }
    }

      当程序运行到invocation.proceedWithInvocation();这句代码时,注释写得很明白,它会去执行链中的下一个拦截器,所以程序又会回到ReflectiveMethodInvocation#proceed()方法。 我们debug跟踪一下。

      通过debug很清楚看到了程序的调用步骤。

      程序本次进入ReflectiveMethodInvocation#proceed()方法后,会进入if条件,然后执行invokeJoinpoint()方法,该方法的底层就是使用反射机制调用自定义的业务方法,于本例而言就是调用addUser()方法。

      调用addUser()方法, 获取方法返回值 ,然后程序又会回到invokeWithinTransaction()方法。

     六. 结束

       Spring的事务的大体流程就说到这里了,示例结合debug应该还是很清楚的,至于其中的许多细节,还有待研究,后面继续补充

  • 相关阅读:
    Android布局1
    QML 自定义折线图
    QML ChartView 画折线图
    操作系统复习笔记
    Redis的使用
    Git的基本使用
    Python json to excel/csv
    .NET中进行Base64加密解密
    用 IIS 7、ARR 與 Velocity 建设高性能的大型网站
    微信突然出现redirect_uri 参数错误
  • 原文地址:https://www.cnblogs.com/z-qinfeng/p/11405183.html
Copyright © 2011-2022 走看看