Spring事务切面_基础(7)

目录

1. 简介

2. 开启事务切面:

传统方式:

 纯注解的方式:

3. 事务切面

 3.1 事务开启类搜集

3.2 将@Bean方法实例化BeanDefinition进行注册

 3.3 Spring 事务切面postprocessor实例化成BeanDefinition并注册

3.4 将支持事务切面生成advisor接口注册

4. 生成事务切面的代理对象,并且将所有的advisor对象实例化Bean对象

5. 详解advisor生成,即@Bean注解的方法是如何被实例化的呢?


1. 简介

上一篇我们已经分析了Spring AOP,其实AOP乍看起来挺难的,读懂代码以后其实还是挺简单的。本篇则是对AOP的进一步分析,即事务切面。

开始本篇之前,我们需要先了解纯注解的方式实例化BeanDefinition的过程,因为现在spring boot和spring cloud比较火,我在分析spring的时候会使用纯注解的方式进行讲解。因此,很有必要了解纯注解的方式实例化BeanDefinition。不了解的话可以先看我的另一篇博客Spring_纯注解实现AOP技术铺垫 (5)_spring aop注解_chen_yao_kerr的博客-CSDN博客

2. 开启事务切面:

传统方式:



    
        
        
        
            classpath:config/core/core.properties
        
    

    
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
            100
        
    
    
        
    

    
    

    
        
        
            classpath:xml/*.xml
        
        
        
    

    
        
        

        

        
    

	

 至于传统方式如何去看源码,我之前也介绍过了。就是根据标签tx找到对应源码包,然后找到spring.handlers文件,如下图:

Spring事务切面_基础(7)_第1张图片

Spring事务切面_基础(7)_第2张图片

 纯注解的方式:

首先需要数据源类:

package com.xuexi.jack.datasource;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
import java.util.HashMap;
import java.util.Map;


/*
*    @PropertySource类似于
* 
        
        
        
            classpath:config/core/core.properties
        
    
*
* */

@Configuration
@PropertySource("classpath:config/core/core.properties")
public class DataSourceConfiguration {

    @Value("${jdbc.driverClassName}")
    private String driverClass;
    @Value("${jdbc.url:jdbc}")
    private String jdbcUrl;
    @Value("${jdbc.username}")
    private String user;
    @Value("${jdbc.password}")
    private String password;

    @Resource
    Environment environment;
    

    @Bean
    public DataSource dynamicDataSource() {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        try {
            comboPooledDataSource.setDriverClass(driverClass);
            comboPooledDataSource.setJdbcUrl(jdbcUrl);
            comboPooledDataSource.setUser(user);
            comboPooledDataSource.setPassword(password);
            comboPooledDataSource.setMinPoolSize(10);
            comboPooledDataSource.setMaxPoolSize(100);
            comboPooledDataSource.setMaxIdleTime(1800);
            comboPooledDataSource.setAcquireIncrement(3);
            comboPooledDataSource.setMaxStatements(1000);
            comboPooledDataSource.setInitialPoolSize(10);
            comboPooledDataSource.setIdleConnectionTestPeriod(60);
            comboPooledDataSource.setAcquireRetryAttempts(30);
            comboPooledDataSource.setBreakAfterAcquireFailure(false);
            comboPooledDataSource.setTestConnectionOnCheckout(false);
            comboPooledDataSource.setAcquireRetryDelay(100);
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }

        Map targetDataSources = new HashMap<>();
        targetDataSources.put("ds1",comboPooledDataSource);

        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(comboPooledDataSource);
        return dynamicDataSource;
    }
}

 需要开启事务的类以及管理数据源的bean,参照传统方式:

package com.xuexi.jack.transaction;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.support.TransactionTemplate;

import javax.sql.DataSource;

@Component
@EnableTransactionManagement(proxyTargetClass = false)
@MapperScan(basePackages = {"com.xuexi.jack.dao"},annotationClass = Repository.class)
public class EnableTransactionManagementBean {

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }

    /*
    * 这样也可以
    * */
    @Bean
    public PlatformTransactionManager annotationDrivenTransactionManager(DataSource dataSource) {
        DataSourceTransactionManager dtm = new DataSourceTransactionManager();
        dtm.setDataSource(dataSource);
        return dtm;
    }

    @Bean
    public TransactionTemplate transactionTemplate(PlatformTransactionManager platformTransactionManager) {
        TransactionTemplate transactionTemplate = new TransactionTemplate();
        transactionTemplate.setTransactionManager(platformTransactionManager);
        return transactionTemplate;
    }
}

这里,我们关注一下@EnableTransactionManagement(proxyTargetClass = false)注解:它import进来 TransactionManagementConfigurationSelector。这个类就是注入事务切面的关键信息的。

Spring事务切面_基础(7)_第3张图片

看一下 TransactionManagementConfigurationSelector类:

Spring事务切面_基础(7)_第4张图片

这2个类具体是干什么的呢?

AutoProxyRegistrar:它是负责注册 支持spring事务切面的postprocessor的,简单点就是注册InfrastructureAdvisorAutoProxyCreator的

Spring事务切面_基础(7)_第5张图片

 Spring事务切面_基础(7)_第6张图片

ProxyTransactionManagementConfiguration 这个类又是干嘛的呢?它就是 创建事务切面的。说的简单点,就是创建类似于Spring AOP中的Advice切面,负责进行拦截、增强事务的:

Spring事务切面_基础(7)_第7张图片

 关于以上2个类,下面还会有更多分析,目前解说这么多,怕一下子说太多了,老铁不理解。

3. 事务切面

Spring的事务切面,也是AOP。我们接着Spring_纯注解实现AOP技术铺垫 (5)_spring aop注解_chen_yao_kerr的博客-CSDN博客 

 进行讲解。在这篇文章的第4节,我们知道纯注解的方式实例化BeanDefinition的入口方法是invokeBeanFactoryPostProcessors()。今天,还是从这个方法进行分析。

继续debug跟进上图的第3步,我们知道,它是用扫描的方式拿到所有的class文件,然后对class文件进行过滤,找到有注解的class对象封装成BeanDefinition。以下内容之前都分析过,简单贴图看一下:

这上面的截图,其实就是很普通的实例化BeanDefinition操作。

 3.1 事务开启类搜集

 在上方的截图中,倒数第3张的方法是 doProcessConfigurationClass(**),通过这个方法进入扫描class和封装并注册beanDefinition的。在我们注册完beanDefinition以后,我们返回到这个方法体中,紧接着就来到了方法 processImports(*****);源码如下:

@Nullable
	protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {

		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// Recursively process any member (nested) classes first
			processMemberClasses(configClass, sourceClass);
		}

		// Process any @PropertySource annotations
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {
			if (this.environment instanceof ConfigurableEnvironment) {
				processPropertySource(propertySource);
			}
			else {
				logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
						"]. Reason: Environment must implement ConfigurableEnvironment");
			}
		}

		// Process any @ComponentScan annotations
		Set componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			for (AnnotationAttributes componentScan : componentScans) {
				// The config class is annotated with @ComponentScan -> perform the scan immediately
				Set scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				// Check the set of scanned definitions for any further config classes and parse recursively if needed
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

		// Process any @Import annotations
		processImports(configClass, sourceClass, getImports(sourceClass), true);

		// Process any @ImportResource annotations
		AnnotationAttributes importResource =
				AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
		if (importResource != null) {
			String[] resources = importResource.getStringArray("locations");
			Class readerClass = importResource.getClass("reader");
			for (String resource : resources) {
				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
				configClass.addImportedResource(resolvedResource, readerClass);
			}
		}

		// Process individual @Bean methods
		Set beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// Process default methods on interfaces
		processInterfaces(configClass, sourceClass);

		// Process superclass, if any
		if (sourceClass.getMetadata().hasSuperClass()) {
			String superclass = sourceClass.getMetadata().getSuperClassName();
			if (superclass != null && !superclass.startsWith("java") &&
					!this.knownSuperclasses.containsKey(superclass)) {
				this.knownSuperclasses.put(superclass, configClass);
				// Superclass found, return its annotation metadata and recurse
				return sourceClass.getSuperClass();
			}
		}

		// No superclass -> processing is complete
		return null;
	}

接下来,一个不得不说的重点方法:

processImports(**): 以开启事务切面的类 EnableTransactionManagementBean为例,再次贴一下源码:

package com.xuexi.jack.transaction;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.support.TransactionTemplate;

import javax.sql.DataSource;

@Component
@EnableTransactionManagement(proxyTargetClass = false)
@MapperScan(basePackages = {"com.xuexi.jack.dao"},annotationClass = Repository.class)
public class EnableTransactionManagementBean {

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }

    /*
    * 这样也可以
    * */
    @Bean
    public PlatformTransactionManager annotationDrivenTransactionManager(DataSource dataSource) {
        DataSourceTransactionManager dtm = new DataSourceTransactionManager();
        dtm.setDataSource(dataSource);
        return dtm;
    }

    @Bean
    public TransactionTemplate transactionTemplate(PlatformTransactionManager platformTransactionManager) {
        TransactionTemplate transactionTemplate = new TransactionTemplate();
        transactionTemplate.setTransactionManager(platformTransactionManager);
        return transactionTemplate;
    }
}

它用到了2个注解 @MapperScan 和 @EnableTransactionManagement。 他们分别import进来2个类MapperScannerRegistrar 和 TransactionManagementConfigurationSelector。

Spring事务切面_基础(7)_第8张图片

 Spring事务切面_基础(7)_第9张图片

 而这个方法就是负责处理这两个类的。今天我们分析的是事务,那么就重点关注如何去处理TransactionManagementConfigurationSelector的。

Spring事务切面_基础(7)_第10张图片

 第一次进入,它就是TransactionManagementConfigurationSelector对象的,然后根据这个对象,拿到它的两个支持spring事务切面的2个类AutoProxyRegistrar 和ProxyTransactionManagementConfiguration, 然后进行递归调用。

第二次进入这个方法,会对以上2个类进行遍历。

AutoProxyRegistrar实现了 ImportBeanDefinitionRegistrar接口,因此会对这个类进行实例化并放入缓存 importBeanDefinitionRegistrars。请记住这个缓存,后面会用

Spring事务切面_基础(7)_第11张图片

 ProxyTransactionManagementConfiguration会进入以下逻辑:

Spring事务切面_基础(7)_第12张图片

首先通过this.importStack.registerImport(***)方法,将实例化后的bean放入缓存imports,然后调用processConfigurationClass(**)方法,又是递归调用。这是我们的主方法,在内部有调用processImports方法才走到这个地方的,现在有调用了processConfigurationClass,很明显是递归。

Spring事务切面_基础(7)_第13张图片

 Spring事务切面_基础(7)_第14张图片

 此时,我们知道,在 EnableTransactionManagementBean对象中使用到了注解@EnableTransactionManagement。 而这个注解负责对spring 事务切面提供支持的,他有2个支持的类:AutoProxyRegistrar 和ProxyTransactionManagementConfiguration。

在实例化ProxyTransactionManagementConfiguration对象以后,我们会对EnableTransactionManagementBean类中含有@Bean注解的方法进行搜集,并封装成BeanMethod对象放入缓存。

此时,整个processImports方法就说完了。

至此,整个processConfigurationClass方法也就结束了。

此处需要注意的一点,无论是根据basePackage包扫描到的类,还是AutoProxyRegistrar 和ProxyTransactionManagementConfiguration,都会放在一个总的缓存中:如下:

Spring事务切面_基础(7)_第15张图片

3.2 将@Bean方法实例化BeanDefinition进行注册

 以上已经完成了BeanDefinition的注册工作了,接下来关注的是beanDefinition的属性设置

 

看一下loadBeanDefinitionsForConfigurationClass方法:

/**
	 * Read a particular {@link ConfigurationClass}, registering bean definitions
	 * for the class itself and all of its {@link Bean} methods.
	 */
	private void loadBeanDefinitionsForConfigurationClass(
			ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

		if (trackedConditionEvaluator.shouldSkip(configClass)) {
			String beanName = configClass.getBeanName();
			if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
				this.registry.removeBeanDefinition(beanName);
			}
			this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
			return;
		}

		if (configClass.isImported()) {
			registerBeanDefinitionForImportedConfigurationClass(configClass);
		}
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}

		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}

EnableTransactionManagementBean是开启我们的Spring事务切面的。而当我们执行上图的的loadbeanDefinition(*****)方法的时候,他会调用loadBeanDefinitionsForConfigurationClass方法。它会拿到EnableTransactionManagementBean类中有@Bean注解的方法,之前说到他们被封装成了BeanMethod类。而此处,我们会拿到这些BeanMethod对象封装成BeanDefinition然后进行注册。具体的封装和注册在 loadBeanDefinitionsForBeanMethod(***)方法中完成。

Spring事务切面_基础(7)_第16张图片

 3.3 Spring 事务切面postprocessor实例化成BeanDefinition并注册

文章开头,我们介绍了纯注解方式开启Spring事务切面,我们说到@EnableTransactionManagement的时候,提到它import进来了TransactionManagementConfigurationSelector类。 如果我们开启的是JDK的动态代理,解JDK支持的Spring AOP操作,提到了2个支持spring事务切面的2个类,AutoProxyRegistrar和TransactionManagementConfigurationSelector:

AutoProxyRegistrar 放入缓存 importBeanDefinitionRegistrars

TransactionManagementConfigurationSelector放入缓存import

Spring事务切面_基础(7)_第17张图片

而此处的loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars())方法,就是调用缓存进行处理的。即调用AutoProxyRegistrar类的。

Spring事务切面_基础(7)_第18张图片

源码如下:

	private void loadBeanDefinitionsFromRegistrars(Map registrars) {
		registrars.forEach((registrar, metadata) ->
				registrar.registerBeanDefinitions(metadata, this.registry));
	}

1. AutoProxyRegistrar:

调用它的registerBeanDefinitions方法,其实核心一点就是注册支持事务切面的postprocessor的,即 InfrastructureAdvisorAutoProxyCreator 接口。

Spring事务切面_基础(7)_第19张图片

 Spring事务切面_基础(7)_第20张图片

 Spring事务切面_基础(7)_第21张图片

此处,需要思考一个问题。 如果Spring AOP 功能 和 Spring事务切面同时开启,而且他们会同时拦截到同一个业务类,那么这个业务类实例肯定是一个代理类。那么这个代理类到底是由Spring AOP生成的动态代理类呢? 还是由Spring 事务切面生成的代理类呢?

其实,答案已经在源码中了。

Spring AOP提供支持的postprocessor是AnnotationAwareAspectJAutoProxyCreator。

Spring事务切面提供支持的postprocessor是InfrastructureAdvisorAutoProxyCreator。

这两个类都实现了AbstractAutoProxyCreator类,而无论是InfrastructureAdvisorAutoProxyCreator还是AnnotationAwareAspectJAutoProxyCreator生成的代理类,最终都是在AbstractAutoProxyCreator内部完成的。

Spring事务切面_基础(7)_第22张图片

 其次。在我们注册InfrastructureAdvisorAutoProxyCreator的过程中,我们会判断该接口是否已经存在。如果存在相同的接口,即都为AbstractAutoProxyCreator类型的接口,那么我们会比较他们的优先级.

Spring事务切面_基础(7)_第23张图片

 那么,又是如何去定义他们的优先级的呢?看一下findPriorityForClass方法:

private static int findPriorityForClass(Class clazz) {
		return APC_PRIORITY_LIST.indexOf(clazz);
	}

Spring事务切面_基础(7)_第24张图片

 原来,所谓的优先级,就是获取对应元素所在的下标索引位置。

InfrastructureAdvisorAutoProxyCreator 下标为 0.

 AspectJAwareAdvisorAutoProxyCreator 下标为1

AnnotationAwareAspectJAutoProxyCreator 下标为2

因此,这个问题的最终答案是: 如果Spring AOP 和事务切面同时开启,那么业务类的代理对象是有AnnotationAwareAspectJAutoProxyCreator生成的,即Spring AOP功能负责生成的。

但是,最终都是由AbstractAutoProxyCreator类生成的。

2. MapperScannerRegistrar

在 EnableTransactionManagementBean 类中,我们还是用到了支持mybatis的注解@MapperScan。在这个注解中import了 MapperScannerRegistrar类。

loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars())方法,也会调用涉及到mybatis的MapperScannerRegistrar类。但这不是我们今天的重点,简单了解一下即可,等到分享mybatis的时候会重点讲。

Spring事务切面_基础(7)_第25张图片

 3. 接口可以实例化吗?

答案是可以的,在纯注解的mybatis连接数据库中,我们都是定义接口的,如下:

package com.xuexi.jack.dao;

import com.xuexi.jack.pojo.ConsultConfigArea;
import com.xuexi.jack.pojo.ZgGoods;
import com.xuexi.jack.pojo.ZgTicket;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Map;

@Repository
public interface CommonMapper {

    @Select("select * from consult_configarea where areaCode=#{areaCode}")
    List queryAreaByAreaCode(Map param);

    @Insert("insert into consult_configarea(AREACODE,AREANAME,STATE) values(#{areaCode},#{areaName},#{state})")
    int addArea(ConsultConfigArea area);

    @Insert("insert into zg_goods (goodCode, goodName, count\n" +
            "\t\t)\n" +
            "\t\tvalues (#{goodCode,jdbcType=VARCHAR}, #{goodName,jdbcType=VARCHAR},\n" +
            "\t\t#{count,jdbcType=INTEGER}\n" +
            "\t\t)")
    int addGood(ZgGoods zgGoods);

    @Select("select * from zg_goods where goodCode=#{goodCode}")
    List queryGoodsByGoodCode(String goodCode);

    @Select("select * from zg_goods")
    List queryAll();

    @Update("update zg_ticket set version=versoin+1 where ticketId = #{ticketId} and version = #{version}")
    int updateLock(Map map);


    @Select("select * from zg_ticket where ticketId = #{ticketId}")
    List queryTicketById(String ticketId);

    @Update("update zg_ticket set ticketCount=ticketCount-#{ticketCount} where ticketId = #{ticketId} and ticketCount >= #{ticketCount}")
    int updateTicket(ZgTicket zgTicket);
}

实例化beanDefinition的过程:

Spring事务切面_基础(7)_第26张图片

至此,关于Spring事务切面实例化BeanDefinition的操作全部讲完了。简单概括一下
1. 首先就是普通的实例化BeanDefinition的操作,我们会把开启Spring事务切面的类也给实例化成BeanDefinition

2. 针对开启事务的BeanDefinition,我们会搜集有@Bean注解的方法,并把他们实例化成 BeanMethod对象

3.针对开启事务的注解,我们会把他们使用的注解进行解析,找到import引入的类,提前给实例化成Bean,并且把这些bean提供的AutoProxyRegistrar也给实例化成Bean

4. 调用loadBeanDefinitions方法,把BeanMethod转成BeanDefinition并注册

5. 最后调用已经实例化好的AutoProxyRegistrar的 registerBeanDefinitions方法,完成事务切面的postprocessor接口的注册,即实例化BeanDefinition并注册。

3.4 将支持事务切面生成advisor接口注册

我们之前说过,所有的beanDefinition都会放入最终的总缓存中。此处,我们还是关注loadBeanDefinitions方法:

Spring事务切面_基础(7)_第27张图片

 此处,我们需要关注的是生成切面Advisor的接口,即ProxyTransactionManagementConfiguration对应的BeanDefinition对象。

Spring事务切面_基础(7)_第28张图片

还是同样的方法 loadBeanDefinitionsForConfigurationClass(***)

Spring事务切面_基础(7)_第29张图片

 上图中,我们会判断当前 ConfigurationClass 对象是不是通过@import注解引入的。如果是的话执行将它注册成BeanDefinition对象。具体步骤如下:

Spring事务切面_基础(7)_第30张图片

 至此,ProxyTransactionManagementConfiguration也被注册成BeanDefinition了。

注册完以后,我们会把ProxyTransactionManagementConfiguration内部含有@Bean注解的方法也给实例化成BeanDefinition对象并进行注册。

Spring事务切面_基础(7)_第31张图片

 Spring事务切面_基础(7)_第32张图片

此时,所有的BeanDefinition准备完毕。

4. 生成事务切面的代理对象,并且将所有的advisor对象实例化Bean对象

 首先,我们需要一个事务类:

package com.xuexi.jack.service.area;

import com.xuexi.jack.pojo.ConsultConfigArea;

import java.util.Map;

public interface AreaService {

    String queryAreaFromDB(Map param);

    String queryAreaFromRedisOne(Map param);

    String queryAreaFromRedisTow(Map param);

    int addArea(ConsultConfigArea area);

}
package com.xuexi.jack.service.area;

import com.xuexi.jack.pojo.ConsultConfigArea;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Map;

@PropertySource("classpath:config/core/core.properties")
@Service
public class AreaServiceImpl implements AreaService {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Value("${jdbc.driverClassName}")
    private String driverClass;
    @Value("${jdbc.url:jdbc}")
    private String jdbcUrl;
    @Value("${jdbc.username}")
    private String user;
    @Value("${jdbc.password}")
    private String password;

   /* @Autowired
    private CommonMapper commonMapper;

    @Autowired
    AreaService areaService;*/

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false, rollbackFor = RuntimeException.class)
    @Override
    public String queryAreaFromDB(Map param) {
      /*  logger.info("================从mysql里面查询数据 事务1========================");
        List areas = commonMapper.queryAreaByAreaCode(param);

        new Thread(() -> areaService.queryAreaFromRedisOne(null)).start();

        areaService.queryAreaFromRedisOne(null);*/
      System.out.println("开始调用 queryAreaFromDB=====");
        return "OK";
    }

    @Transactional
    @Override
    public String queryAreaFromRedisOne(Map param) {
        logger.info("================从mysql里面查询数据 事务2========================");
        return "OK";
    }

    @Override
    public String queryAreaFromRedisTow(Map param) {
        return null;
    }

    @Transactional(propagation = Propagation.NESTED)
    @Override
    public int addArea(ConsultConfigArea area) {
        /*int i = commonMapper.addArea(area);*/
        return 1;
    }
}

这里需要强调的一点是,advisor是可能会提前实例化成Bean对象的。因为我们spring肯定会管理很多的类,而每一个对象实例化成Bean对象以后,我们都会调用 initializeBean 方法判断当前的Bean是否需要生成代理类。因此,在Bean实例化完以后第一次调用initializeBean 方法的时候,会调用事务切面支持的postprocessor进行找切面的工作,我们会拿到所有的advisor的beanDefinition对象进行实例化Bean的操作。

因此,在我们调用事务管理的业务类的时候,advisor其实已经是实例化好的Bean对象了,可以直接拿到Bean对象。下面,我们看一下具体的代码:

Spring事务切面_基础(7)_第33张图片

也就是说,在实例化完我们自定义的扫描类 ComponentScanBean时候,会调用initializeBean 方法,判断当前类是否需要生成代理对象的时候,就会把所有的advisor全部实例化成Bean对象。看一下ComponentScanBean的源码:

package com.xuexi.jack.bean;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Service;

@Service
@ComponentScan(basePackages = {"com.xuexi"})
public class ComponentScanBean {

//    @Bean
//    public void xx() {
//        System.out.println("==");
//    }
}

看看具体的实例化advisor过程:

1. 首先是实例化Bean完以后调用initializeBean,判断是否需要生成代理类

Spring事务切面_基础(7)_第34张图片

2. 进入initializeBean方法内部调用动态代理的postprocessor接口,这里需要关注的是InfrastructureAdvisorAutoProxyCreator

Spring事务切面_基础(7)_第35张图片

 Spring事务切面_基础(7)_第36张图片

 3. InfrastructureAdvisorAutoProxyCreator是 AbstractAutoProxyCreator的子类,因此会直接调用父类的 postProcessAfterInitialization 方法:

Spring事务切面_基础(7)_第37张图片

4. 而 wrapIfNecessary 方法,就是我们找advisor 和 生成代理类的方法。代理类的生成我就不重点说了,不懂的可以看我另一篇Spring AOP的博客,里面说的很清楚Spring之AOP技术 (6)_chen_yao_kerr的博客-CSDN博客

接下来,我们针对找事务切面advisor的过程梳理一下。

Spring事务切面_基础(7)_第38张图片

5. 看一下具体的找事务切面的advisor的过程

Spring事务切面_基础(7)_第39张图片

 debug进入这个方法

Spring事务切面_基础(7)_第40张图片

继续进入方法:

Spring事务切面_基础(7)_第41张图片

上一节我们说过,含有@Bean注解的方法,我们也会实例化成BeanDefinition对象的,而此处就是遍历所有的BeanDefinitionNames,然后找到是advisor类型的beanDefinition,返回他们的Name。

接下来,还是findAdvisorBeans 这个方法,代码继续往下走。 我们会遍历这些name,然后将这些name对象的BeanDefinition实例化成Bean对象,也就是提前把所有的advisor对象都实例化成Bean了,这就是所有的切面。

Spring事务切面_基础(7)_第42张图片

至此,我们所有的advisor全部被实例化好了。

等到我们实例化含有事务注解的业务类的时候,也就是上方贴出的AreaServiceImpl对象的时候,我们还是会调用initializeBean方法,判断是否需要生成代理类。此时,我们还是会进入AbstractAutoProxyCreator的 wrapIfNecessary方法,此时就可以直接拿到刚刚实例化好的advisor然后生成代理对象了。

5. 详解advisor生成,即@Bean注解的方法是如何被实例化的呢?

上一节说到调用getBean方法进行实例化advisor操作,而具体是怎么做的呢?

其实,我们拿到的advisor方法的具体名称是org.springframework.transaction.config.internalTransactionAdvisor,然后进行实例化的

Spring事务切面_基础(7)_第43张图片

 按照这个方法往下跟,我们会创建Bean,但是在创建的时候,我们会判断是否有factoryMethod, 如果有,就会进入处理factoryMethod的相关方法,这个知识点我们之前是没有讲过的,重点:

Spring事务切面_基础(7)_第44张图片

 Spring事务切面_基础(7)_第45张图片

 Spring事务切面_基础(7)_第46张图片

还是这个方法内部,继续往下走:

Spring事务切面_基础(7)_第47张图片

 此处,我们就是我们实例化含有@Bean注解方法的核心代码处,它使用到了factoBean。

debug进入 instantiate方法,这个方法,看看它到底干了啥?

Spring事务切面_基础(7)_第48张图片

进入这个方法内部,我们发现了反射调用:

Spring事务切面_基础(7)_第49张图片 原来是通过反射调用的方式,去调用我们工厂类对应的生成advisor的、含有@Bean注解的方法。这也解释了我们之前什么要提前实例化工厂类(ProxyTransactionManagementConfiguration)

接下来就是进入方法体内部执行了,可能里面还会有很多调用。此处,我们就以最简单的例子进行说明,不扯其他的了。

Spring事务切面_基础(7)_第50张图片

 最后返回advisor对象进行封装交给spring进行管理。

至此,Spring事务切面,从BeanDefinition 到 实例化Bean 的流程就全部讲解完毕了。下一章,我们分享事务的使用。

你可能感兴趣的:(Spring源码,spring,java,spring,boot)