【小家Spring】从基于@Transactional全注解方式的声明式事务入手,彻底掌握Spring事务管理的原理

2019-09-03 15:36:53 浏览数 (1)

前言

上篇文章:

【小家Spring】Spring-jdbc的使用以及Spring事务管理的8种方式介绍(声明式事务 编程式事务)

介绍了Spring事务的众多使用方式,其中讲到全注解@Transactional方式的时候一笔带过了,那么本文就以当下最流行的Spring事务的使用方式:全注解的@Transactional使用方式为切入点,扒开Spring事务管理的神秘面纱~

全注解@Transactional方式的Spring事务

SpringBoot大行其道的今天,基于XML配置的Spring Framework的使用方式注定已成为过去式。

注解驱动应用,面向元数据编程已然成受到越来越多开发者的偏好了,毕竟它的便捷程度、优势都是XML方式不可比拟的。

对SpringBoot有多了解,其实就是看你对Spring Framework有多熟悉~ 比如SpringBoot大量的模块装配的设计模式,其实它属于Spring Framework提供的能力

@Transactional的使用

1、开启注解驱动

代码语言:javascript复制
@EnableTransactionManagement // 开启注解驱动
@Configuration
public class JdbcConfig { ... }

提示:使用@EnableTransactionManagement注解前,请务必保证你已经配置了至少一个PlatformTransactionManager的Bean,否则会报错。(当然你也可以实现TransactionManagementConfigurer来提供一个专属的,只是我们一般都不这么去做~~~)

2、在你想要加入事务的方法上(或者类(接口)上)标注@Transactional注解

代码语言:javascript复制
@Service
public class HelloServiceImpl implements HelloService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional
    @Override
    public Object hello() {
        // 向数据库插入一条记录
        String sql = "insert into user (name,age) values ('fsx',21)";
        jdbcTemplate.update(sql);

        // 做其余的事情  可能抛出异常
        System.out.println(1 / 0);
        return "service hello";
    }
}

单元测试:

代码语言:javascript复制
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {RootConfig.class, JdbcConfig.class})
public class TestSpringBean {

    @Autowired
    private HelloService helloService;

    @Test
    public void test1() {
        System.out.println(helloService.getClass()); //class com.sun.proxy.$Proxy29
        helloService.hello();
    }

}

就这么简单,事务就生效了(这条数据并没有insert成功~)。

从使用步骤上,有没有一种似曾相识的感觉??

没错,特别特别的像@Async或者@Scheduled的使用。其实,原理和@Async也非常的类似(其实还有有本质区别的,一个借助的自动代理创建器,一个自己使用的后置处理器),因此强烈建议可议先参阅博文:

【小家Spring】Spring异步处理@Async的使用以及原理、源码分析(@EnableAsync)

还有这个:

【小家Spring】Spring AOP的核心类:AbstractAdvisorAutoProxy自动代理创建器深度剖析(AnnotationAwareAspectJAutoProxyCreator)


接下来分析注解驱动事务的原理,同样的我们从@EnableTransactionManagement开始:

@EnableTransactionManagement
代码语言:javascript复制
@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;
}

简直不要太面熟好不好,属性和@EnableAsync注解的一毛一样。不同之处只在于@Import导入器导入的这个类,但是我们依然能发现端倪:它也是个ImportSelector

@EnableAsync注解源码:

代码语言:javascript复制
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
	// 支持自定义注解类型 去支持异步~~~
	Class<? extends Annotation> annotation() default Annotation.class;
	boolean proxyTargetClass() default false;
	AdviceMode mode() default AdviceMode.PROXY;
	int order() default Ordered.LOWEST_PRECEDENCE;
}
TransactionManagementConfigurationSelector

它所在的包为org.springframework.transaction.annotation,jar属于:spring-tx(若引入了spring-jdbc,这个jar会自动导入

代码语言:javascript复制
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			// 很显然,绝大部分情况下,我们都不会使用AspectJ的静态代理的~~~~~~~~
			// 这里面会导入两个类~~~
			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);
	}

}

依然可以看出,和@EnableAsync导入的AsyncConfigurationSelector如出一辙,都继承自AdviceModeImportSelector,这就是为何我强烈建议先看关于@Async那篇博文的原因,毕竟模式一样,触类旁通,一通百通~

AdviceModeImportSelector目前所知的三个子类是:AsyncConfigurationSelectorTransactionManagementConfigurationSelectorCachingConfigurationSelector。由此可见后面还会着重分析的Spring的缓存体系@EnableCaching,模式也是和这个极其类似的~~~

AutoProxyRegistrar

从名字是意思是:自动代理注册器。它是个ImportBeanDefinitionRegistrar,可以实现自己向容器里注册Bean的定义信息

代码语言:javascript复制
// @since 3.1
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		boolean candidateFound = false;
		
		// 这里面需要特别注意的是:这里是拿到所有的注解类型~~~而不是只拿@EnableAspectJAutoProxy这个类型的
		// 原因:因为mode、proxyTargetClass等属性会直接影响到代理得方式,而拥有这些属性的注解至少有:
		// @EnableTransactionManagement、@EnableAsync、@EnableCaching等~~~~
		// 甚至还有启用AOP的注解:@EnableAspectJAutoProxy它也能设置`proxyTargetClass`这个属性的值,因此也会产生关联影响~
		Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
		for (String annoType : annoTypes) {
			AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
			if (candidate == null) {
				continue;
			}
			// 拿到注解里的这两个属性
			// 说明:如果你是比如@Configuration或者别的注解的话  他们就是null了
			Object mode = candidate.get("mode");
			Object proxyTargetClass = candidate.get("proxyTargetClass");

			// 如果存在mode且存在proxyTargetClass 属性
			// 并且两个属性的class类型也是对的,才会进来此处(因此其余注解相当于都挡外面了~)
			if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
					Boolean.class == proxyTargetClass.getClass()) {
		
				// 标志:找到了候选的注解~~~~
				candidateFound = true;
				if (mode == AdviceMode.PROXY) {
					// 这一部是非常重要的~~~~又到了我们熟悉的AopConfigUtils工具类,且是熟悉的registerAutoProxyCreatorIfNecessary方法
					// 它主要是注册了一个`internalAutoProxyCreator`,但是若出现多次的话,这里不是覆盖的形式,而是以第一次的为主
					// 当然它内部有做等级的提升之类的,这个之前也有分析过~~~~
					AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
					
					// 看要不要强制使用CGLIB的方式(由此可以发现  这个属性若出现多次,是会是覆盖的形式)
					if ((Boolean) proxyTargetClass) {
						AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
						return;
					}
				}
			}
		}
		
		// 如果一个都没有找到(我在想,肿么可能呢?)
		// 其实有可能:那就是自己注入这个类,而不是使用注解去注入(但并不建议这么去做)
		if (!candidateFound && logger.isInfoEnabled()) {
			// 输出info日志(注意并不是error日志)
		}
	}

}

这一步最重要的就是向Spring容器注入了一个自动代理创建器:org.springframework.aop.config.internalAutoProxyCreator,并且看看是采用CGLIB还是JDK代理。

跟踪AopConfigUtils的源码你会发现,事务这块向容器注入的是一个InfrastructureAdvisorAutoProxyCreator,它主要是读取Advisor类,并对符合的bean进行二次代理。在Spring AOP博文中有过详细介绍,这里略过~ 参考:【小家Spring】Spring AOP的核心类:AbstractAdvisorAutoProxy自动代理创建器深度剖析(AnnotationAwareAspectJAutoProxyCreator)

ProxyTransactionManagementConfiguration

它是一个@Configuration,所以看看它向容器里注入了哪些Bean

代码语言:javascript复制
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	// 这个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());
		// 顺序由@EnableTransactionManagement注解的Order属性来指定 默认值为:Ordered.LOWEST_PRECEDENCE
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}

	// TransactionAttributeSource 这种类特别像 `TargetSource`这种类的设计模式
	// 这里直接使用的是AnnotationTransactionAttributeSource  基于注解的事务属性源~~~
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

	// 事务拦截器,它是个`MethodInterceptor`,它也是Spring处理事务最为核心的部分
	// 请注意:你可以自己定义一个TransactionInterceptor(同名的),来覆盖此Bean(注意是覆盖)
	// 另外请注意:你自定义的BeanName必须同名,也就是必须名为:transactionInterceptor  否则两个都会注册进容器里面去~~~~~~
	@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;
	}

}

// 父类(抽象类)  它实现了ImportAware接口  所以拿到@Import所在类的所有注解信息
@Configuration
public abstract class AbstractTransactionManagementConfiguration implements ImportAware {

	@Nullable
	protected AnnotationAttributes enableTx;
	/**
	 * Default transaction manager, as configured through a {@link TransactionManagementConfigurer}.
	 */
	// 此处:注解的默认的事务处理器(可议通过实现接口TransactionManagementConfigurer来自定义配置)
	// 因为事务管理器这个东西,一般来说全局一个就行,但是Spring也提供了定制化的能力~~~
	@Nullable
	protected PlatformTransactionManager txManager;

	@Override
	public void setImportMetadata(AnnotationMetadata importMetadata) {
		// 此处:只拿到@EnableTransactionManagement这个注解的就成~~~~~ 作为AnnotationAttributes保存起来
		this.enableTx = AnnotationAttributes.fromMap(importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName(), false));
		// 这个注解是必须的~~~~~~~~~~~~~~~~
		if (this.enableTx == null) {
			throw new IllegalArgumentException("@EnableTransactionManagement is not present on importing class "   importMetadata.getClassName());
		}
	}

	// 这里和@Async的处理一样,配置文件可以实现这个接口。然后给注解驱动的给一个默认的事务管理器~~~~
	// 设计模式都是想通的~~~
	@Autowired(required = false)
	void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
		if (CollectionUtils.isEmpty(configurers)) {
			return;
		}
		// 同样的,最多也只允许你去配置一个~~~
		if (configurers.size() > 1) {
			throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
		}
		TransactionManagementConfigurer configurer = configurers.iterator().next();
		this.txManager = configurer.annotationDrivenTransactionManager();
	}


	// 注册一个监听器工厂,用以支持@TransactionalEventListener注解标注的方法,来监听事务相关的事件
	// 后面会专门讨论,通过事件监听模式来实现事务的监控~~~~
	@Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
		return new TransactionalEventListenerFactory();
	}

}

关于事务相关的基础类打点,建议先参阅:

【小家Spring】Spring事务相关的基础类打点(spring-jdbc和spring-tx两个jar),着重讲解AnnotationTransactionAttributeSource

下面重中之重来了,那就是BeanFactoryTransactionAttributeSourceAdvisor这个增强器

BeanFactoryTransactionAttributeSourceAdvisor

首先看它的父类AbstractBeanFactoryPointcutAdvisor这个之前在讲述AOP的时候已经大篇幅解释过:

【小家Spring】Spring AOP之Advisor、PointcutAdvisor、IntroductionAdvisor、IntroductionInterceptor(引介增强)

父类是一个和Bean工厂有关的Advisor。

再看自己,它是一个和Bean工厂和事务都有关系的Advisor

从上面的配置类可议看出,它是new出来一个。

使用的Advice为:advisor.setAdvice(transactionInterceptor()),既容器内的事务拦截器

使用的事务属性源为:advisor.setTransactionAttributeSource(transactionAttributeSource()),既一个new AnnotationTransactionAttributeSource()支持三种事务注解来标注~~~

代码语言:javascript复制
// @since 2.5.5
// 它是一个AbstractBeanFactoryPointcutAdvisor ,关于这个Advisor 请参阅之前的博文讲解~~~
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
	
	@Nullable
	private TransactionAttributeSource transactionAttributeSource;
	
	// 这个很重要,就是切面。它决定了哪些类会被切入,从而生成的代理对象~ 
	// 关于:TransactionAttributeSourcePointcut 下面有说~
	private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
		// 注意此处`getTransactionAttributeSource`就是它的一个抽象方法~~~
		@Override
		@Nullable
		protected TransactionAttributeSource getTransactionAttributeSource() {
			return transactionAttributeSource;
		}
	};
	
	// 可议手动设置一个事务属性源~
	public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
		this.transactionAttributeSource = transactionAttributeSource;
	}

	// 当然我们可以指定ClassFilter  默认情况下:ClassFilter classFilter = ClassFilter.TRUE;  匹配所有的类的
	public void setClassFilter(ClassFilter classFilter) {
		this.pointcut.setClassFilter(classFilter);
	}

	// 此处pointcut就是使用自己的这个pointcut去切入~~~
	@Override
	public Pointcut getPointcut() {
		return this.pointcut;
	}

}

下面当然要重点看看TransactionAttributeSourcePointcut,它是怎么切入的

TransactionAttributeSourcePointcut

这个就是事务的匹配Pointcut切面,决定了哪些类需要生成代理对象从而应用事务。

代码语言:javascript复制
// 首先它的访问权限事default 显示是给内部使用的
// 首先它继承自StaticMethodMatcherPointcut   所以`ClassFilter classFilter = ClassFilter.TRUE;` 匹配所有的类
// 并且isRuntime=false  表示只需要对方法进行静态匹配即可~~~~
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {

	// 方法的匹配  静态匹配即可(因为事务无需要动态匹配这么细粒度~~~)
	@Override
	public boolean matches(Method method, Class<?> targetClass) {
		// 实现了如下三个接口的子类,就不需要被代理了  直接放行
		// TransactionalProxy它是SpringProxy的子类。  如果是被TransactionProxyFactoryBean生产出来的Bean,就会自动实现此接口,那么就不会被这里再次代理了
		// PlatformTransactionManager:spring抽象的事务管理器~~~
		// PersistenceExceptionTranslator对RuntimeException转换成DataAccessException的转换接口
		if (TransactionalProxy.class.isAssignableFrom(targetClass) ||
				PlatformTransactionManager.class.isAssignableFrom(targetClass) ||
				PersistenceExceptionTranslator.class.isAssignableFrom(targetClass)) {
			return false;
		}
		
		// 重要:拿到事务属性源~~~~~~
		// 如果tas == null表示没有配置事务属性源,那是全部匹配的  也就是说所有的方法都匹配~~~~(这个处理还是比较让我诧异的~~~)
		// 或者 标注了@Transaction这样的注解的方法才会给与匹配~~~
		TransactionAttributeSource tas = getTransactionAttributeSource();
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}	
	...
	// 由子类提供给我,告诉事务属性源~~~~ 我才好知道哪些方法我需要切嘛~~~
	@Nullable
	protected abstract TransactionAttributeSource getTransactionAttributeSource();
}

关于matches方法的调用时机:只要是容器内的每个Bean,都会经过AbstractAutoProxyCreator#postProcessAfterInitialization从而会调用wrapIfNecessary方法,因此容器内所有的Bean的所有方法在容器启动时候都会执行此matche方法,因此请注意缓存的使用~

这样结合这篇博文:

【小家Spring】Spring事务相关的基础类打点(spring-jdbc和spring-tx两个jar),着重讲解AnnotationTransactionAttributeSource

就能知道Spring最终会给哪些类生成代理对象,事务可以作用在哪些方法上

真正的执行事务方法,还是在TransactionInterceptor这个增强器里,这个因为比价比较复杂,所以以一篇单独摘取出来详细讲解~~~请持续关注,就在下一篇哦~

@Transactional简单解释

这个事务注解可以用在类上,也可以用在方法上。

  • 将事务注解标记到服务组件类级别,相当于为该服务组件的每个服务方法都应用了这个注解
  • 事务注解应用在方法级别,是更细粒度的一种事务注解方式

注意 : 如果某个方法和该方法所属类上都有事务注解属性,优先使用方法上的事务注解属性。

另外,Spring 支持三个不同的事务注解 :

  1. Spring 事务注解 org.springframework.transaction.annotation.Transactional(纯正血统,官方推荐)
  2. JTA事务注解 javax.transaction.Transactional
  3. EJB 3 事务注解 javax.ejb.TransactionAttribute

上面三个注解虽然语义上一样,但是使用方式上不完全一样,若真要使其它的时请注意各自的使用方式~

代码语言:javascript复制
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {

	// value 和 transactionManager 属性 它们两个是一样的意思。当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器。
	@AliasFor("transactionManager")
	String value() default "";
	 // @since 4.2
	@AliasFor("value")
	String transactionManager() default "";

	Propagation propagation() default Propagation.REQUIRED; //事务的传播行为
	Isolation isolation() default Isolation.DEFAULT; // 事务的隔离级别
	int timeout() default TransactionDefinition.TIMEOUT_DEFAULT; //事务的超时时间,默认值为-1
	boolean readOnly() default false; //是否只读 默认是false
	
	// 需要回滚的异常 可以指定多个异常类型   不指定默认只回滚RuntimeException和Error
	Class<? extends Throwable>[] rollbackFor() default {};
	String[] rollbackForClassName() default {};
	
	// 不需要回滚的异常们~~~
	Class<? extends Throwable>[] noRollbackFor() default {};
	String[] noRollbackForClassName() default {};
}
自定义注解驱动的事务管理器 TransactionManagementConfigurer

注解的事务管理器会有一个人默认的,然后@Transaction里也可以通过value属性进行制定~~。

改变默认的有一个非常优雅的方式,那就是使用TransactionManagementConfigurer接口来提供:

代码语言:javascript复制
@EnableTransactionManagement
@Configuration
public class JdbcConfig implements TransactionManagementConfigurer {
	
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource);
        return dataSourceTransactionManager;
    }

	// 复写提供一个即可。可以自己new一个,当然也可议向着一样从容器中获取~~~
    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
    	// 直接使用容器内的事务管理器~~~
        return transactionManager(dataSource());
    }
	
}
思考:若既有@EnableAspectJAutoProxy又有@EnableTransactionManagement,那么自动代理创建器怎么注入谁呢?和注解的标注的先后顺序有关吗?

根据之前的分析和本文的分析,我们知道:

  • @EnableAspectJAutoProxy会像容器注入AnnotationAwareAspectJAutoProxyCreator
  • @EnableTransactionManagement会像容器注入InfrastructureAdvisorAutoProxyCreator 那么它俩同时使用时,形如下面:
代码语言:javascript复制
@EnableTransactionManagement
@EnableAspectJAutoProxy
@Configuration
public class JdbcConfig {
	...
}

那么最终会注入哪个代理创建类呢?

其实之前我们有分析过,核心代码在这:AopConfigUtils#registerOrEscalateApcAsRequired方法

代码语言:javascript复制
public abstract class AopConfigUtils {
	...
	@Nullable
	private static BeanDefinition registerOrEscalateApcAsRequired(
			Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
		
		// 可以发现这里有一个很巧妙的处理:会对自动代理创建器进行升级~~~~
		// 所以如果你第一次进来的是`InfrastructureAdvisorAutoProxyCreator`,第二次进来的是`AnnotationAwareAspectJAutoProxyCreator`,那就会取第二次进来的这个Class
		// 反之则不行。这里面是维护的一个优先级顺序的,具体参看本类的static代码块,就是顺序  最后一个`AnnotationAwareAspectJAutoProxyCreator`才是最为强大的
		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) {
					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;
	}
	...
}

从上面的分析可以知道:无论你的这些注解有多少个,无论他们的先后顺序如何,它内部都有咯优先级提升的机制来保证向下的覆盖兼容。因此一般情况下,我们使用的都是最高级的AnnotationAwareAspectJAutoProxyCreator这个自动代理创建器~~~

0 人点赞