上节《springboot ApplicationContext之finishBeanFactoryInitialization(getBean())下》我们遗留了一个问题: InfrastructureAdvisorAutoProxyCreator是什么时候加载到spring容器的,又是怎么产生代理的呢? 我们就来解答下,但是跟今天的主题@Transactional又有什么关系呢?跟我往下看!
springboot 中@Transactional起作用是启用了**@EnableTransactionManagement**注解,而这个注解的默认加载是在TransactionAutoConfiguration中,这个类定义在spring.factories中对应的key=org.springframework.boot.autoconfigure.EnableAutoConfiguration(关于这个注解如何使用,及作用,看相关的springboot starter)。
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(PlatformTransactionManager.class)
@AutoConfigureAfter({ JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class })
@EnableConfigurationProperties(TransactionProperties.class)
public class TransactionAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public TransactionManagerCustomizers platformTransactionManagerCustomizers(
ObjectProvider<PlatformTransactionManagerCustomizer<?>> customizers) {
return new TransactionManagerCustomizers(customizers.orderedStream().collect(Collectors.toList()));
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(ReactiveTransactionManager.class)
public TransactionalOperator transactionalOperator(ReactiveTransactionManager transactionManager) {
return TransactionalOperator.create(transactionManager);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnSingleCandidate(PlatformTransactionManager.class)
public static class TransactionTemplateConfiguration {
@Bean
@ConditionalOnMissingBean(TransactionOperations.class)
public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {
return new TransactionTemplate(transactionManager);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(TransactionManager.class)
@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
public static class EnableTransactionManagementConfiguration {
@Configuration(proxyBeanMethods = false)
@EnableTransactionManagement(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
matchIfMissing = false)
public static class JdkDynamicAutoProxyConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableTransactionManagement(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
public static class CglibAutoProxyConfiguration {
}
}
}
这个配置类,装了一个个内部类,我们看跟@Transactional相关的EnableTransactionManagementConfiguration 类,该类中定义了两个内部类JdkDynamicAutoProxyConfiguration 、CglibAutoProxyConfiguration 区别在于spring.aop.proxy-target-class的处理:
@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;
}
看看这个引入类都引进了啥
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
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,又是个引入类, if (mode == AdviceMode.PROXY) {
//重点看下这里注入的类
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
最终注入InfrastructureAdvisorAutoProxyCreator,这就回答了开头是如何注入的问题了!good! -
ProxyTransactionManagementConfiguration
这里要注意下:springboot 默认开启@EnableAspectJAutoProxy注解(详情看AopAutoConfiguration),会导致在容器中不是InfrastructureAdvisorAutoProxyCreator,而是AnnotationAwareAspectJAutoProxyCreator,本文是在加了spring.aop.auto=false 关闭状态!
这里会有个优先级,spring容器中beanname=org.springframework.aop.config.internalAutoProxyCreator 会只有一个类型!例如我们加了@EnableTransactionManagement注解,又同时有@EnableAspectJAutoProxy注解,这时候AnnotationAwareAspectJAutoProxyCreator就会覆盖InfrastructureAdvisorAutoProxyCreator注入到容器中。
public abstract class AopConfigUtils {
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
static {
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
@Nullable
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) {
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;
}
}
当然我们今天的主题才开始,我们总结当前的引入类,spring 一串串的记不住,还是看个图吧
标注颜色的是跟事务相关的类,其它的异步、缓存跟当前的逻辑相同,看蓝色的三个引入类
- BeanFactoryTransactionAttributeSourceAdvisor
- AnnotationTransactionAttributeSource
- TransactionInterceptor
它们三个的关系是,看下ProxyTransactionManagementConfiguration类
@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;
}
}
好了目前为止,springboot对@Transactional注解,前奏已经完成,准备好进入了。
当我们定义了一个类
@Service
public class TestC {
@Autowired
private TestMapper testMapper;
public void say1(){
TestC o = (TestC)AopContext.currentProxy();
o.say2();
}
@Transactional
public void say2(){
Map<Object, Object> hashMap = new HashMap<>();
hashMap .put("id",1);
testMapper.say(hashMap);
}
}
在spring加载TestC的时候,会被beanpostprocessor(InfrastructureAdvisorAutoProxyCreator)拦截产出代理类,具体什么时候调用《springboot ApplicationContext之finishBeanFactoryInitialization(getBean())下》
现在来看看代理类是怎么产生的,拦截的入口就是wrapIfNecessary方法 分成两个步骤:
-
查看当前bean满足条件的advisor、advice 首先会从当前容器中,查找类型是Advisor,当然当前满足条件的是之前注入到容器中的BeanFactoryTransactionAttributeSourceAdvisor,然后判断改advisor是否可以对当前类进行拦截就是图中的参canApply方法 两个判断: classFiltermatch methodMatcher.match,满足条件的是(重点来了),还是分两步:循环当前类的方法(如果类中加了事务注解但是没方法,不会拦截),对当前的方法进行判断。方法需要满足以下条件: 1) 方法修饰符必须是public
2)对应的方法上存在@Transactional
3)如果2不满足,对应方法的类存在@Transactional
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
if (specificMethod != method) {
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
return null;
}
-
存在满足条件的进行创建代理,代理(当前使用cglib)后的对象信息,主要加了拦截器DynamicAdvisedInterceptor 这时候Testc的代理对象已经产生,当调调用Testc.say2()方法,会被DynamicAdvisedInterceptor拦截器拦截
判断是否匹配的方式,跟wrapIfNecessary基本一致,唯一区别是针对当前的方法(什么内部调用事务失效的原因),而不是当前类的所有方法。匹配后看下,调用的流程:开启事务–》执行方法–》提交事务。 刚才提到,内部调用失效的解决方式是要设置:暴露代理,覆盖默认注解@EnableAspectJAutoProxy(exposeProxy = true),就会执行AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry)
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
@EnableAspectJAutoProxy(exposeProxy = true)
@Service
public class TestC {
@Autowired
private TestMapper testMapper;
public void say1(){
TestC o = (TestC)AopContext.currentProxy();
o.say2();
}
@Transactional
public void say2(){
Map<Object, Object> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.put("id",1);
testMapper.say(objectObjectHashMap);
}
}
想象下,当我们获取到代理对象(TestC)AopContext.currentProxy(),再执行调用方法say2(), 是不是又会被DynamicAdvisedInterceptor拦截,事务是不是又起作用了呢。
最后 最后扣了一张网上的图,前面几种我想应该是清楚了吧!
|