spring事务源码-代理对象生成过程解析

spring事务源码

spring事务的源码,要从@EnableTransactionManagement注解拉开序幕

首先,如果我们要使用spring事务,只需要在配置类上添加@EnableTransactionManagement注解,并且在业务方法上添加@Transactional注解即可(以spring项目为例,SpringBoot项目后面博客中再另说)

@EnableTransactionManagement

@Target({
    
    ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({
    
    TransactionManagementConfigurationSelector.class})
public @interface EnableTransactionManagement {
    
    
  /*
  * proxyTargetClass
	 *  true:
	 *    无论目标方法是否实现了接口,都使用CGLIB代理
	 *  false:
	 *    如果目标方法实现了接口,使用JDK动态代理
	 *    如果目标方法没有实现接口,使用CGLIB代理
	 */
    boolean proxyTargetClass() default false;

  /**
	 * @return
	 *
	 * 事务通知模式(切面织入方式):
	 *  默认是代理模式
	 */
    AdviceMode mode() default AdviceMode.PROXY;

    int order() default 2147483647;
}

可以看到,这个注解也挺简单的,就是通过@Import注解,引入了另外一个bean,通过查看TransactionManagementConfigurationSelector的类继承关系,可以发现,这个类实现了ImportSelector注解,所以,会实现selectImports()方法,在该方法中,注入了两个重要的bean

  1. AutoProxyRegistrar
  2. ProxyTransactionManagementConfiguration

AutoProxyRegistrar

AutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,所以,在registerBeanDefinitions方法中,注入一个bean

InfrastructureAdvisorAutoProxyCreator
可以发现,这个类是一个后置处理器,继承了InstantiationAwareBeanPostProcessor

所以:这就是@EnableTransactionManagement的第一个作用,注入了一个后置处理器,这个后置处理器就是用来对事务注解进行增强的

在这里插入图片描述

ProxyTransactionManagementConfiguration

该类只有一个注解@Configuration,所以该类是一个配置类,在该类中,通过三个@Bean注解,向spring容器中注入了事务执行时要用到的组件

/**
	 * @return
	 * 注入事务增强器
	 * 这里是创建一个advisor,然后设置切点(TransactionInterceptor)和通知(TransactionAttributeSource)
	 * 这里的BeanFactoryTransactionAttributeSourceAdvisor类似于aop中的advisor
	 */
	@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;
	}

	/**
	 * @return
	 * 往spring容器中注入事务解析器(解析事务注解上的各个参数)
	 * 在执行第八个后置处理器的时候,判断是否需要增强的时候,会解析transaction注解
	 *
	 * 这里在new AnnotationTransactionAttributeSource()对象的时候,有一个非常关键的点:
	 * 	publicMethodsOnly  这里在调用构造函数的时候,默认初始化该值为true;该值的意思是:只允许public方法进行事务代理
	 *
	 * 	在后面判断是否可以对方法进行增强的时候,会判断该值,以及对应method是否是public,如果是非public修饰的方法,直接return null,不进行代理增强
	 */
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

	/**
	 * @return
	 * 定义事务拦截器,并将事务拦截器注入到spring容器中
	 */
	@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;
	}

所以:该类是给spring容器中,注入了三个bean,分别是:事务拦截器、事务解析器、事务增强器

判断是否需要代理

我们知道,AOP的动态代理是在第八个后置处理器调用的时候,判断是否需要增强,如果需要增强,就通过JDK或者CGLIB进行代理,注解版的事务,也是利用了AOP实现的

在这里插入图片描述

这是在添加事务注解的方法对应的bean在初始化时,调用到第八个后置处理器的时候,判断是否需要进行增强的调用链,由于这里和AOP是一样的调用链,所以中间的这些过程就不做过多解释了,直接看最后匹配是否需要增强的代码

我们可以暂时先认为:methodMatcher.matches(method, targetClass) 如果这里返回的是true,就是需要进行增强,返回false,就继续遍历下一个方法,进行判断

org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#matches
// 这里是用获取到的tas来判断method是否有添加注解,如果这里返回false,就表示当前method无需增强,返回true,需要增强
public boolean matches(Method method, Class<?> targetClass) {
    
    
		TransactionAttributeSource tas = this.getTransactionAttributeSource();
		return tas == null || tas.getTransactionAttribute(method, targetClass) != null;
}


org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute
  
  /**
  * 这里是在解析method之前,先判断下之前是否已经解析过
  */
@Override
	@Nullable
	public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    
    
		if (method.getDeclaringClass() == Object.class) {
    
    
			return null;
		}

		// First, see if we have a cached value.
		/**
		 * 根据method和targetClass生成一个cacheKey
		 * 如果这里已经对方法进行了一次解析,就会把解析之后获取到的TransactionAttribute对象和对应的key存入到一个map集合中
		 * 这样下次再有地方用到这个方法的时候,就无须再次解析,直接从map中获取即可
		 * 如果这里没有获取到,返回的null,就将value设置为null,写入到map中
		 * 如果获取到对应的txAttr,就setDescriptor设置下该属性,然后写入到map集合中
		 */
		Object cacheKey = getCacheKey(method, targetClass);
		TransactionAttribute cached = this.attributeCache.get(cacheKey);
		if (cached != null) {
    
    
			// Value will either be canonical value indicating there is no transaction attribute,
			// or an actual transaction attribute.
			if (cached == NULL_TRANSACTION_ATTRIBUTE) {
    
    
				return null;
			}
			else {
    
    
				return cached;
			}
		}
		else {
    
    
			// We need to work it out.
			/**
			 * 如果是第一次进入到这里,一定会走这个方法
			 * 这里就是判断当前方法是否是public,是否有添加@Transactional注解
			 */
			TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
			// Put it in the cache.
			/**
			 * 如果当前方法没有添加事务注解,或者不满足生成代理对象的要求,就将value设置为null,存入到这个map集合中
			 */
			if (txAttr == null) {
    
    
				this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
			}
			else {
    
    
        // 这里是满足增强的条件,将txAttr放到map集合中,并返回
				String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
				if (txAttr instanceof DefaultTransactionAttribute) {
    
    
					((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
				}
				if (logger.isDebugEnabled()) {
    
    
					logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
				}
				this.attributeCache.put(cacheKey, txAttr);
			}
			return txAttr;
		}
	}

下面这个方法主要是判断当前method是否是public修饰的,然后在方法中调用findTransactionAttribute来判断方法或者class是否有添加@Transactional注解

	@Nullable
	protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		// Don't allow no-public methods as required.
		/**
		 * 判断当前方法是否是public修饰的,以及是否只支持public方法进行事务代理
		 */
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			return null;
		}

		// The method may be on an interface, but we need attributes from the target class.
		// If the target class is null, the method will be unchanged.
		Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

		// First try is the method in the target class.
		/**
		 * 2.查找当前方法是否有添加@Transactional注解,如果有添加,就解析对应的注解信息
		 * 下面有几个重复查找的动作,这里还没有搞明白依次获取到的是什么,总之都是判断入参的这个方法或者class有没有事务注解(大致的意思应该是先判断方法有没有添加注解,然后再判断类上是否添加事务注解)
		 */
		TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
		if (txAttr != null) {
			return txAttr;
		}

		// Second try is the transaction attribute on the target class.
		txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
		if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
			return txAttr;
		}

		if (specificMethod != method) {
			// Fallback is to look at the original method.
			txAttr = findTransactionAttribute(method);
			if (txAttr != null) {
				return txAttr;
			}
			// Last fallback is the class of the original method.
			txAttr = findTransactionAttribute(method.getDeclaringClass());
			if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
				return txAttr;
			}
		}
		return null;
	}
org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#determineTransactionAttribute

org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)

// 这个方法中调用了findMergedAnnotationAttributes来判断当前element是否有事务注解,
// 然后调用parseTransactionAnnotation,解析@Transactional注解的配置
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
    
    
		AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
				element, Transactional.class, false, false);
		if (attributes != null) {
    
    
			return parseTransactionAnnotation(attributes);
		}
		else {
    
    
			return null;
		}
	}

这里是解析@Transactional注解对应的配置信息,并将配置信息存入到了一个TransactionAttribute对象中

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;
	}

截止到这里,基本上就解析完毕了;如果有配置@Transactional注解,那么在最上面的methodMatcher.matches(method, targetClass) 方法就会返回true,返回true,那么spring后置处理器就任务当前类中有事务方法,需要进行增强,那就会生成代理对象,和aop的逻辑是一样的:
根据是否实现了接口,来判断是使用CGLIB代理还是使用JDK代理;所以:@Transactional注解就类似于aop中的切点(只有添加了@Transactional注解的方法,才会生成代理对象,在被调用的时候,进行事务拦截器进行处理)

spring事务应用

1.spring事务不支持非public方法的原因

如果在非public方法上添加事务注解,在发生异常的时候,事务是不会回滚的,也即:事务是不生效的

原因:

1.我们知道,spring事务其实就是利用了AOP动态代理的知识,也就是说:如果加了@Transactional注解的方法,spring会为其类生成代理对象,在调用的时候,会通过拦截器来调用
2.如果说spring不支持非public方法,那实现原理也简单:在判断是否需要进行动态代理的时候,首先判断下当前class对应的method是否是public的,如果是非public,就不进行后面的判断,直接返回false,无需代理即可;这样的话,就不会为类生成代理对象


下面这个方法在源码解析中有说到过,是bean在初始化的过程中,执行到第八个后置处理器的时候,调用的,判断是否需要对bean进行代理;在这个问题中,就不详细解释了

​ 我们只需要知道:如果这里返回的是null,就不会对该类和该方法进行增强,如果返回了TransactionAttribute对象,就会进行增强

org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#computeTransactionAttribute

@Nullable
	protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    
    
		// Don't allow no-public methods as required.
		/**
		 * 判断当前方法是否是public修饰的,以及是否只支持public方法进行事务代理
		 */
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
    
    
			return null;
		}

		// The method may be on an interface, but we need attributes from the target class.
		// If the target class is null, the method will be unchanged.
		Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

		// First try is the method in the target class.
		/**
		 * 2.查找当前方法是否有添加@Transactional注解,如果有添加,就解析对应的注解信息
		 */
		TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
		if (txAttr != null) {
    
    
			return txAttr;
		}

		// Second try is the transaction attribute on the target class.
		txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
		if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
    
    
			return txAttr;
		}

		if (specificMethod != method) {
    
    
			// Fallback is to look at the original method.
			txAttr = findTransactionAttribute(method);
			if (txAttr != null) {
    
    
				return txAttr;
			}
			// Last fallback is the class of the original method.
			txAttr = findTransactionAttribute(method.getDeclaringClass());
			if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
    
    
				return txAttr;
			}
		}

		return null;
	}

针对这个问题,只需要关注这一行代码就可以

if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			return null;
}

/**
* 这里就是判断当前方法是否是public方法修饰的
*/
public static boolean isPublic(int mod) {
  	return (mod & PUBLIC) != 0;
}

org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#allowPublicMethodsOnly
@Override
protected boolean allowPublicMethodsOnly() {
		return this.publicMethodsOnly;
}

在AnnotationTransactionAttributeSource这个类中,搜索可以发现,默认的都是true,并且这个类的初始化是在
ProxyTransactionManagementConfiguration中,在这个ProxyTransactionManagementConfiguration中,通过@Bean注解,注入了一个TransactionAttributeSource对象,
  
  @Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

所以:这个参数铁定是true;也就是说,只允许public方法才能进行事务代理

猜你喜欢

转载自blog.csdn.net/CPLASF_/article/details/108694947