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( )メソッドが実装されます。このメソッドでは、2つの重要なBeanが注入されます。

  1. AutoProxyRegistrar
  2. ProxyTransactionManagementConfiguration

AutoProxyRegistrar

AutoProxyRegistrarはImportBeanDefinitionRegistrarインターフェースを実装しているため、registerBeanDefinitionsメソッドでBeanを注入します。

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

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

ここに画像の説明を挿入

ProxyTransactionManagementConfiguration

このクラスにはアノテーション@Configurationが1つしかないため、このクラスはコンフィギュレーションクラスです。このクラスでは、トランザクションの実行に使用されるコンポーネントをSpringコンテナに挿入するために3つの@Beanアノテーションが使用されます。

/**
	 * @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コンテナーに注入され、3つのBeanは、トランザクションインターセプター、トランザクションパーサー、トランザクションエンハンサーです。

エージェントが必要かどうかを判断する

AOPの動的プロキシは、8番目のポストプロセッサが呼び出されたときに拡張が必要かどうかを判断します。拡張が必要な​​場合は、JDKまたはCGLIBを介してプロキシされます。アノテーションバージョンのトランザクションもAOPによって実現されます。 。

ここに画像の説明を挿入

これは、トランザクションアノテーションを追加するメソッドに対応するBeanが初期化され、8番目のポストプロセッサが呼び出されたときに拡張コールチェーンが必要かどうかを判断するためです。これは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;
		}
	}

次のメソッドは、主に現在のメソッドがパブリックに変更されているかどうかを判断し、メソッドでfindTransactionAttributeを呼び出して、メソッドまたはクラスに@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を返します。その後、スプリングポストプロセッサーが現在のタスクを実行します。クラス拡張が必要な​​トランザクションメソッドがあり、プロキシオブジェクトが生成され、aopのロジックは同じです。
インターフェイスが実装されているかどうかに応じて、CGLIBプロキシとJDKプロキシのどちらを使用するかが判断されます。 ;したがって:@Transactionalアノテーションはaopに似ていますカットインのポイント(@Transactionalアノテーションを持つメソッドのみがプロキシオブジェクトを生成し、呼び出されると、トランザクションインターセプターがそれを処理します)

春のトランザクションアプリケーション

1.Springトランザクションが非公開メソッドをサポートしない理由

非公開メソッドにトランザクションアノテーションを追加すると、例外が発生したときにトランザクションがロールバックされません。つまり、トランザクションは有効ではありません。

理由:

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


ソースコードの次の分析メソッドは、初期化プロセスのBeanであり、呼び出されたときにBeanプロキシかどうかを判断するための8番目のポストプロセッサの実装です。この問題では、説明しません。詳細に

知っておく必要があるのは、ここで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