Spring面向切面编程

2019/01/25 Spring

Spring面向切面编程

@EnableTransactionManagement

我们在Springboot 中开始事务管理很简单,使用 @EnableTransactionManagement 注解即可。 那么也就说明 @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;

}

很明显了@Import(TransactionManagementConfigurationSelector.class) 指向我们去看 TransactionManagementConfigurationSelector 的实现。

TransactionManagementConfigurationSelector

TransactionManagementConfigurationSelector 间接实现了 ImportSelector 接口,ImportSelector 会根据 selectImports 返回的字符串数组(一般是类的全路径名) 通过反射加载该类并注册到Spring容器中。 所以我们这里必然来看一下 selectImports 方法了,ImportSelector #selectImports 的实现在其父类AdviceModeImportSelector#selectImports

	@Override
	public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
		// 获取注解类型, 这里是 EnableTransactionManagement
		Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
		Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");
		// 解析出 @EnableTransactionManagement 注解的参数
		AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
		if (attributes == null) {
			throw new IllegalArgumentException(String.format(
					"@%s is not present on importing class '%s' as expected",
					annType.getSimpleName(), importingClassMetadata.getClassName()));
		}
		// 获取mode属性。EnableTransactionManagement 默认mode =  AdviceMode.PROXY
		AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());
		// 调用 TransactionManagementConfigurationSelector#selectImports
		String[] imports = selectImports(adviceMode);
		if (imports == null) {
			throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
		}
		return imports;
	}
	...
		@Nullable
	protected abstract String[] selectImports(AdviceMode adviceMode);

可以知道了 这里是将 protected abstract String[] selectImports(AdviceMode adviceMode); 返回的值返回给 Spring。这里我们看看在 TransactionManagementConfigurationSelector 中的 selectImports(AdviceMode adviceMode) 方法的实现。

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		// 默认值 是 PROXY。个人猜测是通过 代理模式实现事务,如果是 ASPECTJ 则是通过 ASPECTJ的方式实现,AspectJ 需要单独引入编译
		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);
	}

}

到这里就可以看到了,默认情况下,我们引入了两个类,AutoProxyRegistrar 和ProxyTransactionManagementConfiguration。

  • AutoProxyRegistrar : 主要是注册了 InfrastructureAdvisorAutoProxyCreator 自动代理创建器。而 InfrastructureAdvisorAutoProxyCreator 的逻辑基本上和 Aop 的逻辑相同
  • ProxyTransactionManagementConfiguration : 注册了事务实现的核心 Bean,包括 BeanFactoryTransactionAttributeSourceAdvisor、TransactionAttributeSource、TransactionInterceptor 等

AutoProxyRegistrar

AutoProxyRegistrar实现了 ImportBeanDefinitionRegistrar 接口,所以我们要去看看他的registerBeanDefinitions 方法的实现。 AutoProxyRegistrar#registerBeanDefinitions 代码如下:

	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		boolean candidateFound = false;
		// 获取 当前类上的所有注解
		Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
		for (String annType : annTypes) {
			// 获取注解的所有属性
			AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
			if (candidate == null) {
				continue;
			}
			// 获取mode、proxyTargetClass 属性
			Object mode = candidate.get("mode");
			Object proxyTargetClass = candidate.get("proxyTargetClass");
			if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
					Boolean.class == proxyTargetClass.getClass()) {
				candidateFound = true;
				// 判断如果是 Proxy 模式,也就是默认模式,注册自动代理创建器
				if (mode == AdviceMode.PROXY) {
					AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
					// 如果需要代理目标列,则强制自动代理创建者使用类代理
					if ((Boolean) proxyTargetClass) {
						AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
						return;
					}
				}
			}
		}
		... 省略日志打印
	}

在这里我们可以看到,registerBeanDefinitions 方法中解析了 事务注解,并注册了自动代理创建器。这里自动代理创建器我们在Aop 源码中提到过,是Aop 创建的核心。

AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)

这一步最主要的作用将自动代理创建器 InfrastructureAdvisorAutoProxyCreator 注册到了 Spring容器中。

经过数次跳转,我们来到了 AopConfigUtils#registerOrEscalateApcAsRequired。其中这

	public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
			"org.springframework.aop.config.internalAutoProxyCreator";
			
	private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);

	static {
		// Set up the escalation list...
		// 事务使用
		APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
		APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
		// Spring aop 使用
		APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
	}
	....
	
	public static BeanDefinition registerAutoProxyCreatorIfNecessary(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
	}
	
	...
		
	// 这里的 cls 是 InfrastructureAdvisorAutoProxyCreator .class
	private static BeanDefinition registerOrEscalateApcAsRequired(
			Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		// 如果有注册,则判断优先级,将优先级的高的保存
		// 如果已经纯在了自动代理创建器,且存在的自动代理创建器与现在的并不一致,那么需要根据优先级来判断到底要使用哪个
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
				int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
				int requiredPriority = findPriorityForClass(cls);
				if (currentPriority < requiredPriority) {
				// 改变bean所对应的className 属性
					apcDefinition.setBeanClassName(cls.getName());
				}
			}
			// 如果已经存在自动代理创建器,并且与将要创建的一致,那么无需再次创建
			return null;
		}

		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
		beanDefinition.setSource(source);
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}

	...
	// 可以看到,所谓的优先级顺序实际上是在 APC_PRIORITY_LIST 集合的顺序
	public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			// 设置 proxyTargetClass 属性
			definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
		}
	}
	
	...
	
	public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			// 设置 exposeProxy 属性
			definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
		}
	}

到这里我们基本可以断定和 Aop 的逻辑基本相同了,只不过事务默认自动注入的自动代理创建器是 InfrastructureAdvisorAutoProxyCreator 类型。 注意:

  • 在上篇Aop 中我们知道 Aop创建的自动代理创建器类型是 AnnotationAwareAspectJAutoProxyCreator,而事务创建的类型是 InfrastructureAdvisorAutoProxyCreator 。
  • 这里之所以 beanName (AUTO_PROXY_CREATOR_BEAN_NAME) 和 bean的类型并不相同,是因为这个beanName 特指内部的自动代理创建器,但是自动创建代理器会对应多种不同的实现方式。比如在默认的事务中,注入的bean类型却为InfrastructureAdvisorAutoProxyCreator,而AOP的实现却是 AnnotationAwareAspectJAutoProxyCreator。
  • 关于自动代理创建器优先级的问题,我们可以看到APC_PRIORITY_LIST 集合的顺序,下标越大,优先级越高。因此可以得知优先级的顺序应该是
  • InfrastructureAdvisorAutoProxyCreator < AspectJAwareAdvisorAutoProxyCreator < AnnotationAwareAspectJAutoProxyCreator

InfrastructureAdvisorAutoProxyCreator

上面我们可以知道,事务将自动代理创建器 InfrastructureAdvisorAutoProxyCreator 注册到了 Spring容器中。这里就跟Aop 基本相同了,下面我们来看看 InfrastructureAdvisorAutoProxyCreator 的内容 可以看到 InfrastructureAdvisorAutoProxyCreator 并没有实现什么逻辑,主要逻辑在其父类 AbstractAutoProxyCreator 中。我们在Aop 中提到过, AbstractAutoProxyCreator 是自动代理创建器的基础。绝大部分逻辑都是在其中实现的。(AbstractAutoProxyCreator 是AbstractAdvisorAutoProxyCreator 的父类,是 InfrastructureAdvisorAutoProxyCreator 的 “爷爷”类)。

public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {

	@Nullable
	private ConfigurableListableBeanFactory beanFactory;


	@Override
	protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		super.initBeanFactory(beanFactory);
		this.beanFactory = beanFactory;
	}

	@Override
	// 校验bean是否合格
	protected boolean isEligibleAdvisorBean(String beanName) {
		return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&
				this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
	}

}

事务中的 findCandidateAdvisors 方法

在这里,我们可以发现的是: Aop 的使用的是 AnnotationAwareAspectJAutoProxyCreator 自动代理创建器;事务使用的是InfrastructureAdvisorAutoProxyCreator自动代理创建器。而Aop代理创建的关键逻辑就自动代理创建器中。

我们对比后两种自动代理创建器后,惊奇的发现,其现实逻辑基本一致。最大的不同之处在于,Aop 重写了 AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors 方法。而事务并没有重写这一部分。 所以事务调用的实际上是 AbstractAdvisorAutoProxyCreator#findCandidateAdvisors。即下面一部分

	protected List<Advisor> findCandidateAdvisors() {
		Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
		return this.advisorRetrievalHelper.findAdvisorBeans();
	}

而Spring aop调用的则是重写后的 AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors

	@Override
	protected List<Advisor> findCandidateAdvisors() {
		// Add all the Spring advisors found according to superclass rules.
		List<Advisor> advisors = super.findCandidateAdvisors();
		// Build Advisors for all AspectJ aspects in the bean factory.
		if (this.aspectJAdvisorsBuilder != null) {
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}

可以清楚的看到,Aop 的重写是加了this.aspectJAdvisorsBuilder.buildAspectJAdvisors() 方法调用,也就是动态生成 Advisor 的部分。

为什么事务实现不需要动态生成Advisor 部分?

何为Aop的切入点多变,即Pointcut的定义规则由代码掌握,我们通过 @Pointcut注解 可以定义一个匹配所有方法的切面,也可以定义一个匹配到指定的方法的切面,对于Spring来说,Spring无法通过一个 Advisor 满足诸多Pointcut 条件,而为了满足这个条件所以需要通过代码来动态解析所有的Pointcut 来封装成一个一个的 Advisor,随后便可以通过 Advisor 来判断该方法是否满足某个 Advisor 的切入要求。 而对于事务来说,启用事务的方法必须要使用 @Transactional 来修饰方法(也可以修饰在类上,但这里为了方便描述直接说方法上,并且在类上使用更符合编程习惯)。也就是说对Spring来说,判断一个方法是否启用事务的依据就是该方法上是否使用了 @Transactional 注解。也就是说,我们仅需要一个 Advisor ,其判断条件是方法是否被@Transactional 注解修饰即可。而既然知道了Pointcut 条件,我们就可以实现编写好满足这个逻辑的 Advisor,在Spring启动时候直接将这个条件的 Advisor 注入到容器中直接使用。 综上,事务并不需要去动态注入 Advisor,而Spring aop 则需要动态注入。

通过上面的分析,我们判断,事务的Advisor 已经事先注入了,然后我们回头看到TransactionManagementConfigurationSelector 中注入的另一个类 ProxyTransactionManagementConfiguration。在 ProxyTransactionManagementConfiguration 中果不其然发现了Advisor 的踪迹。

ProxyTransactionManagementConfiguration

ProxyTransactionManagementConfiguration 代码如下,并没有逻辑,就是将几个Bean注入的到容器中。不过这几个bean可都是关键bean,所以我们需要对其中的bean进行分析。

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
			TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {

		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(TransactionAttributeSource transactionAttributeSource) {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		interceptor.setTransactionAttributeSource(transactionAttributeSource);
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}

}
  • BeanFactoryTransactionAttributeSourceAdvisor : 事务的增强器,该方法是否开始事务,是否需要代理该类都在该类中判断
  • TransactionAttributeSource : 保存了事务相关的一些信息资源。
  • TransactionInterceptor : 事务拦截器,事务生成代理类时使用的代理拦截器,编写了事务的规则

BeanFactoryTransactionAttributeSourceAdvisor

public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {

	@Nullable
	private TransactionAttributeSource transactionAttributeSource;

	private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
		@Override
		@Nullable
		protected TransactionAttributeSource getTransactionAttributeSource() {
			return transactionAttributeSource;
		}
	};


	/**
	 * Set the transaction attribute source which is used to find transaction
	 * attributes. This should usually be identical to the source reference
	 * set on the transaction interceptor itself.
	 * @see TransactionInterceptor#setTransactionAttributeSource
	 */
	public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
		this.transactionAttributeSource = transactionAttributeSource;
	}

	/**
	 * Set the {@link ClassFilter} to use for this pointcut.
	 * Default is {@link ClassFilter#TRUE}.
	 */
	public void setClassFilter(ClassFilter classFilter) {
		this.pointcut.setClassFilter(classFilter);
	}

	@Override
	public Pointcut getPointcut() {
		return this.pointcut;
	}

}

这个根据上面的分析,我们可以知道这个是事务判断的核心,BeanFactoryTransactionAttributeSourceAdvisor 是Advisor 子类,那么我们可以知道其中有两个关键属性: Pointcut(判断是否可以作用于当前方法) 和 Advice(作用于当前方法的具体逻辑)。

通过 Aop文章的分析我们可以知道,Advisor 判断一个方法是否匹配,是通过其 Pointcut.matchs 属性来判断的。然后我们通过上面的代码,发现其 Pointcut 的实现类是 TransactionAttributeSourcePointcut ,也就是说,一个方法是否需要使用事务,是通过 TransactionAttributeSourcePointcut#matches 方法判断的。

Search

    微信好友

    博士的沙漏

    Table of Contents