zoukankan      html  css  js  c++  java
  • Springboot Actuator之十一:actuator transaction

    前言
    spring boot 的自动化配置其实就是在spring 的基础上做的封装,在我们之前对mvc,aop的自动化配置中可以发现–> 只是在spring 的基础上添加了一些特性,可以认为只是一个spring的应用.那么,关于transaction的配置也同样.

    解析
    和aop自动配置一样,在/META-INF/spring.factories中配置有关transaction的有2个:

    org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
    org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration
    我们这里只分析 TransactionAutoConfiguration

    TransactionAutoConfiguration 声明了如下注解:

    @Configuration
    @ConditionalOnClass(PlatformTransactionManager.class)
    @AutoConfigureAfter({ JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
    DataSourceTransactionManagerAutoConfiguration.class,
    Neo4jDataAutoConfiguration.class })
    @EnableConfigurationProperties(TransactionProperties.class)
    1
    2
    3
    4
    5
    6
    @Configuration–>配置类
    @ConditionalOnClass(PlatformTransactionManager.class)–> 当前类路径下存在PlatformTransactionManager.class 时该配置生效
    @AutoConfigureAfter({ JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class,Neo4jDataAutoConfiguration.class })–> 在JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class,Neo4jDataAutoConfiguration.class 之后才解析该类.
    @EnableConfigurationProperties(TransactionProperties.class)–> 可通过以下2个属性来配置:

    spring.transaction.defaultTimeout–> 配置事务的默认超时时间
    spring.transaction.rollbackOnCommitFailure–> 配置是否在事务提交失败时回滚
    在 spring boot 源码解析11-ConfigurationClassPostProcessor类加载解析 中 我们知道了spring boot 解析配置的类的属性,对于当前来说,由于TransactionAutoConfiguration有2个内部类,因此会处理内部类:

    TransactionTemplateConfiguration, 其注解如下:

    @Configuration
    @ConditionalOnSingleCandidate(PlatformTransactionManager.class)
    1
    2
    @Configuration –> 配置类
    @ConditionalOnSingleCandidate(PlatformTransactionManager.class)–> 当PlatformTransactionManager类型的bean存在并且当存在多个bean时指定为Primary的PlatformTransactionManager存在时,该配置类才进行解析
    由于TransactionAutoConfiguration是在DataSourceTransactionManagerAutoConfiguration之后才被解析处理的,而在DataSourceTransactionManagerAutoConfiguration中配置了transactionManager,因此, TransactionTemplateConfiguration 会被处理.

    TransactionTemplateConfiguration只有一个被@Bean注解的方法,代码如下:

    @Bean
    @ConditionalOnMissingBean
    public TransactionTemplate transactionTemplate() {
    return new TransactionTemplate(this.transactionManager);
    }
    1
    2
    3
    4
    5
    当beanFactory中不存在TransactionTemplate类型的bean时,注册一个id为transactionTemplate,类型为TransactionTemplate的bean

    EnableTransactionManagementConfiguration,注解如下:

    @Configuration
    @ConditionalOnBean(PlatformTransactionManager.class)
    @ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
    1
    2
    3
    @Configuration –> 配置类
    @ConditionalOnBean(PlatformTransactionManager.class) –> 当beanFactory中存在PlatformTransactionManager类型的bean时该配置生效
    @ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)–> 当beanFactory不存在AbstractTransactionManagementConfiguration类型的bean时生效.
    由于EnableTransactionManagementConfiguration只有内部类,同样首先解析内部类:

    JdkDynamicAutoProxyConfiguration:

    @Configuration
    @EnableTransactionManagement(proxyTargetClass = false)
    @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
    public static class JdkDynamicAutoProxyConfiguration {
    }
    1
    2
    3
    4
    5
    @Configuration–> 配置类
    @EnableTransactionManagement(proxyTargetClass = false)–>启用TransactionManagement, proxyTargetClass = false,表示是面向接口代理.关于这个注解,我们后面会分析.
    @ConditionalOnProperty(prefix = “spring.aop”, name = “proxy-target-class”, havingValue = “false”, matchIfMissing = false)–> 配置有spring.aop.proxy-target-class = false时生效,如果没配置,则不生效
    CglibAutoProxyConfiguration,代码如下:

    @Configuration
    @EnableTransactionManagement(proxyTargetClass = true)
    @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
    public static class CglibAutoProxyConfiguration {
    }
    1
    2
    3
    4
    5
    @Configuration–> 配置类
    @EnableTransactionManagement(proxyTargetClass = true)–>启用TransactionManagement, proxyTargetClass = true,表示是使用cglib进行代理.关于这个注解,我们后面会分析.
    @ConditionalOnProperty(prefix = “spring.aop”, name = “proxy-target-class”, havingValue = “true”, matchIfMissing = true)–> 配置有spring.aop.proxy-target-class = true时生效,如果没配置,则默认生效
    因此,在默认情况下,EnableTransactionManagementConfiguration 生效的是JdkDynamicAutoProxyConfiguration.

    @EnableTransactionManagement 注解如下:

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(TransactionManagementConfigurationSelector.class)
    public @interface EnableTransactionManagement {
    // false--> jdk动态代理,true-->cglib代理,默认使用的是jdk动态代理
    boolean proxyTargetClass() default false;
    // 表明transactional 切面是如何织入的,默认是代理
    AdviceMode mode() default AdviceMode.PROXY;
    // aop的优先级
    int order() default Ordered.LOWEST_PRECEDENCE;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    该注解通过@Import(TransactionManagementConfigurationSelector.class)注解导入了TransactionManagementConfigurationSelector,类图如下:

    因此会调用TransactionManagementConfigurationSelector#selectImports.代码如下:

    protected String[] selectImports(AdviceMode adviceMode) {
    switch (adviceMode) {
    case PROXY:
    return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
    case ASPECTJ:
    return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
    default:
    return null;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    如果是AdviceMode.PROXY,返回org.springframework.context.annotation.AutoProxyRegistrar,org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
    如果是AdviceMode.ASPECTJ,返回org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration
    否则,返回null
    此时,由于传入的是AdviceMode.PROXY,因此执行第1步

    接着,将第一步的返回值传入processImports中继续调用.

    由于AutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,因此会将其实例化后,加入到JdkDynamicAutoProxyConfiguration所对应的ConfigurationClass中的importBeanDefinitionRegistrars
    ProxyTransactionManagementConfiguration类既不是ImportSelector的子类也不是ImportBeanDefinitionRegistrar的子类,因此会调用ConfigurationClassParser#processConfigurationClass处理.该类的类图如下:

    由于AbstractTransactionManagementConfiguration实现了ImportAware接口.因此会调用其setImportMetadata方法.代码如下:

    public void setImportMetadata(AnnotationMetadata importMetadata) {
    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());
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    从@EnableTransactionManagement 中获取配置信息,封装为AnnotationAttributes.如果@EnableTransactionManagement没有配置属性的话,就会返回null,此时就会抛出IllegalArgumentException.

    同时在AbstractTransactionManagementConfiguration声明了一个被@Autowired(required = false)注解的方法:

    @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();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    当获得该bean时,会将beanFactory中所有TransactionManagementConfigurer类型得到bean传递给该函数
    如果configurers为空,直接return
    如果有多个TransactionManagementConfigurer类型的bean,则抛出IllegalStateException
    获得PlatformTransactionManager
    注意: TransactionManagementConfigurer在spring 中没有实现,因此正常情况下是不会有TransactionManagementConfigurer类型的bean

    同时在AbstractTransactionManagementConfiguration中注册了一个id为org.springframework.transaction.config.internalTransactionalEventListenerFactory,类型为TransactionalEventListenerFactory,角色为内部使用的bean,代码如下:

    @Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionalEventListenerFactory transactionalEventListenerFactory() {
    return new TransactionalEventListenerFactory();
    }
    1
    2
    3
    4
    5
    6
    ProxyTransactionManagementConfiguration中很简单了,声明了3个bean,分别如下:

    id 为org.springframework.transaction.config.internalTransactionAdvisor,类型为BeanFactoryTransactionAttributeSourceAdvisor,角色为内部使用的bean.代码如下:

    @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
    BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
    advisor.setTransactionAttributeSource(transactionAttributeSource());
    advisor.setAdvice(transactionInterceptor());
    advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
    return advisor;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    实例化BeanFactoryTransactionAttributeSourceAdvisor
    配置 transactionAttributeSource
    配置 Advice–>切面
    配置aop优先级–>默认Integer.MAX_VALUE
    id为transactionAttributeSource,类型为TransactionAttributeSource,角色为内部使用的bean.代码如下:

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionAttributeSource transactionAttributeSource() {
    return new AnnotationTransactionAttributeSource();
    }
    1
    2
    3
    4
    5
    id为transactionInterceptor,类型为TransactionInterceptor,角色为内部使用的bean.代码如下:

    @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;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    视线回到TransactionAutoConfiguration,内部类处理完之后,由于TransactionAutoConfiguration声明了@EnableConfigurationProperties(TransactionProperties.class) 注解,而@EnableConfigurationProperties注解通过@Import(EnableConfigurationPropertiesImportSelector.class)引入了EnableConfigurationPropertiesImportSelector.

    因此,接下来会调用ConfigurationClassParser#processImports

    由于EnableConfigurationPropertiesImportSelector是ImportSelector的实现,调用其selectImports方法返回的是ConfigurationPropertiesBeanRegistrar,ConfigurationPropertiesBindingPostProcessorRegistrar.

    由于ConfigurationPropertiesBeanRegistrar, ConfigurationPropertiesBindingPostProcessorRegistrar是ImportBeanDefinitionRegistrar的实现,添加到TransactionAutoConfiguration对应的importBeanDefinitionRegistrars中.

    接着,处理TransactionAutoConfiguration中被@bean注解的方法—> 只有一个,代码如下:

    @Bean
    @ConditionalOnMissingBean
    public TransactionManagerCustomizers platformTransactionManagerCustomizers(
    ObjectProvider<List<PlatformTransactionManagerCustomizer<?>>> customizers) {
    return new TransactionManagerCustomizers(customizers.getIfAvailable());
    }
    1
    2
    3
    4
    5
    6
    TransactionAutoConfiguration 配置类解析完之后,会调用ConfigurationClassBeanDefinitionReader#loadBeanDefinitions.会依次处理TransactionAutoConfiguration配置类中生成的ConfigurationClass

    ProxyTransactionManagementConfiguration 对应的ConfigurationClass,由于是被JdkDynamicAutoProxyConfiguration导入的,因此会调用ConfigurationClassBeanDefinitionReader#registerBeanDefinitionForImportedConfigurationClass方法,代码如下:

    private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
    AnnotationMetadata metadata = configClass.getMetadata();
    AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);

    ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
    configBeanDef.setScope(scopeMetadata.getScopeName());
    String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
    AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);

    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
    configClass.setBeanName(configBeanName);

    if (logger.isDebugEnabled()) {
    logger.debug("Registered bean definition for imported class '" + configBeanName + "'");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    向BeanDefinitionRegistry进行注册.

    同时,由于在ProxyTransactionManagementConfiguration中定义了4个@bean方法,因此会依次调用loadBeanDefinitionsForBeanMethod进行注册.

    JdkDynamicAutoProxyConfiguration 是被EnableTransactionManagementConfiguration导入,因此同样会调用ConfigurationClassBeanDefinitionReader#registerBeanDefinitionForImportedConfigurationClass方法,进行注册.

    由于在JdkDynamicAutoProxyConfiguration中importBeanDefinitionRegistrars 配置有AutoProxyRegistrar,因此会调用AutoProxyRegistrar#registerBeanDefinitions.代码如下:

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    boolean candidateFound = false;
    Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
    for (String annoType : annoTypes) {
    AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
    if (candidate == null) {
    continue;
    }
    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;
    if (mode == AdviceMode.PROXY) {
    AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
    if ((Boolean) proxyTargetClass) {
    AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
    return;
    }
    }
    }
    }
    if (!candidateFound) {
    String name = getClass().getSimpleName();
    // log
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    获得importingClassMetadata中的注解类型
    依次遍历,如果遍历到@EnableTransactionManagement 注解

    如果@EnableTransactionManagement 配置的mode 为PROXY,则注册类型为InfrastructureAdvisorAutoProxyCreator,id为org.springframework.aop.config.internalAutoProxyCreator的bean
    如果@EnableTransactionManagement 配置的proxyTargetClass为true,则向beanFactory中id为org.springframework.aop.config.internalAutoProxyCreator的bean添加proxyTargetClass的属性,值为true
    如果最终没有找到@EnableTransactionManagement,则打印日志

    EnableTransactionManagementConfiguration 是被TransactionAutoConfiguration 导入.因此会调用ConfigurationClassBeanDefinitionReader#registerBeanDefinitionForImportedConfigurationClass方法进行注册

    TransactionTemplateConfiguration 是被TransactionTemplateConfiguration导入的, 因此会调用ConfigurationClassBeanDefinitionReader#registerBeanDefinitionForImportedConfigurationClass方法进行注册.同时由于声明了一个被@bean注解的方法,因此会调用loadBeanDefinitionsForBeanMethod进行注册
    TransactionAutoConfiguration 是被启动类导入,因此会调用ConfigurationClassBeanDefinitionReader#registerBeanDefinitionForImportedConfigurationClass方法进行注册.

    同时由于有一个被@bean注解的方法,因此会调用loadBeanDefinitionsForBeanMethod进行注册
    最后,由于通过@EnableConfigurationProperties间接导入了2个BeanDefinitionsFromRegistrar.依次会依次调用其registerBeanDefinitions方法.

    ConfigurationPropertiesBeanRegistrar–> 会向BeanDefinitionRegistry注册一个id为spring.transaction-org.springframework.boot.autoconfigure.transaction.TransactionProperties,类型为TransactionProperties的bean
    ConfigurationPropertiesBindingPostProcessorRegistrar–>
    如果BeanDefinitionRegistry中不存id为org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor的bean,则:

    注册id为org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor,类型为ConfigurationBeanFactoryMetaData的bean
    注册id为org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.store,类型为ConfigurationBeanFactoryMetaData的bean
    注意:关于解析配置类的流程在spring boot 源码解析11-ConfigurationClassPostProcessor类加载解析中详细解析

    解析流程图如下:

    加载流程就比较简单了,这里就不画了
    ---------------------
    版权声明:本文为CSDN博主「一个努力的码农」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/qq_26000415/article/details/79021958

  • 相关阅读:
    jquery 实现 返回顶部
    js 10秒倒计时 功能
    2019.6.10 工作日志
    2019.4.25 工作日志
    2019.4.22 工作日志
    2019.4.13 工作日志
    2019.3.12 工作日志
    2019.1.22 工作日志
    2019.1.18 工作日志
    2019.1.14 工作日志
  • 原文地址:https://www.cnblogs.com/duanxz/p/11328700.html
Copyright © 2011-2022 走看看