前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【小家Spring】从基于@Transactional全注解方式的声明式事务入手,彻底掌握Spring事务管理的原理

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

作者头像
YourBatman
发布2019-09-03 15:36:53
1.2K0
发布2019-09-03 15:36:53
举报
文章被收录于专栏:BAT的乌托邦BAT的乌托邦

前言

上篇文章:

【小家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这个自动代理创建器~~~

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年04月29日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 全注解@Transactional方式的Spring事务
    • @Transactional的使用
      • @EnableTransactionManagement
        • TransactionManagementConfigurationSelector
          • AutoProxyRegistrar
            • ProxyTransactionManagementConfiguration
            • BeanFactoryTransactionAttributeSourceAdvisor
              • TransactionAttributeSourcePointcut
                • @Transactional简单解释
                  • 自定义注解驱动的事务管理器 TransactionManagementConfigurer
                    • 思考:若既有@EnableAspectJAutoProxy又有@EnableTransactionManagement,那么自动代理创建器怎么注入谁呢?和注解的标注的先后顺序有关吗?
                    相关产品与服务
                    容器服务
                    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档