关于后端:声明式事务与AOP

1次阅读

共计 27925 个字符,预计需要花费 70 分钟才能阅读完成。

原始博文链接

出发点

闲来无事回顾几个我的项目中的一些内容,把一些反复代码用 AOP 重新处理了一下,定义切入点时采纳了自定义注解的模式,起因是这样最精准、最容易管制,当然毛病是须要手动把注解加到各个办法下来。我的项目里还有用到申明式事务(@Transactional)和申明式缓存(@Cacheable),所以有的办法就会存在 3 个以上的切面相干注解,注解一多就发现对它们的执行程序机理的了解有些含糊,遂打算从新理一遍 Spring AOP 的内容,回顾一把这个经典到不能再经典的工具。为了不便,底子还是用的 SpringBoot,顺便也回顾下 SpringBoot 中事务、AOP 等主动配置的相干内容,剖析剖析源码。本文默认您曾经有对 Spring AOP 与申明式事务管理的根本认知,采纳的版本信息:SpringBoot 2.3.3.RELEASE(Spring 5.2.8.RELEASE)

申明式事务原理

首先整顿下申明式事务,在 SpringBoot 环境下不须要独自引入事务相干的依赖或者独自增加启用事务的注解,通常引入相干的长久层依赖就能够间接应用 @Transactional 这个注解,而如果要应用 Spring AOP 您须要显式引入依赖项spring-boot-starter-aop。申明式事务实质上也是 AOP 思维的产物,那么为什么没有诸如spring-boot-starter-transaction,为什么应用申明式事务不须要引入 spring-aop 是个值得思考的问题。

对于一般 Spring 我的项目来说,应用申明式事务须要显式进行指定。xml 配置中须要增加标签 <tx:annotation-driven>(使@Transactional 失效)或者应用标签 <tx:advice> 来申明事务切入;应用 Java config 模式则须要在配置类上增加注解 @EnableTransactionManage。而 SpringBoot 能够不精确的形容为更高级的 Java config,咱们晓得 SpringBoot 自带的主动配置类都在spring-boot-autoconfigure 包下,很容易找到事务相干的主动配置类org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration

@Configuration(proxyBeanMethods = false)
// 依赖 PlatformTransactionManager, 该类位于 spring-tx 包下
@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()));
    }

    // reactive 相干,能够暂不思考
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnSingleCandidate(ReactiveTransactionManager.class)
    public TransactionalOperator transactionalOperator(ReactiveTransactionManager transactionManager) {return TransactionalOperator.create(transactionManager);
    }

    // 配置 TransactionTemplate
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnSingleCandidate(PlatformTransactionManager.class)
    public static class TransactionTemplateConfiguration {

        @Bean
        @ConditionalOnMissingBean(TransactionOperations.class)
        public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {return new TransactionTemplate(transactionManager);
        }

    }

    // 事务的次要配置内容,依据应用的代理形式分成两种:jdk proxy 和 cglib proxy
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnBean(TransactionManager.class)
    // 这个 contion 意味着你能够被动应用 @EnableTransactional,不采纳如下的默认配置
    @ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
    public static class EnableTransactionManagementConfiguration {@Configuration(proxyBeanMethods = false)
        // 应用与一般 java config 雷同的注解
        @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 {}}

}

因而还是回到了 @EnableTransactionManagement 这注解上,值得额定留神的一点是以后版本 SpringBoot 环境下该注解的 proxyTargetClass 属性默认设置为 true(matchIfMissing 的作用),这与注解属性自身的默认值(false)不同,也就是说 SpringBoot 默认采纳 CGLIB 作为动静代理解决方案,有对于这一点的具体能够参考这个 issue 的探讨。接下来持续深刻该注解:

@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;}

该注解次要的性能就是引入 TransactionManagementConfigurationSelector,其作为接口ImportSelector 的实现类目标是引入一些 Configuration 配置类:

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

    // 依据 @EnableTransactionManagement 注解的 mode 属性来确定引入的配置类
    @Override
    protected String[] selectImports(AdviceMode adviceMode) {switch (adviceMode) {
            case PROXY:
                // 默认应用 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);
    }

}

以默认的 PROXY 模式为例(ASPECTJ 须要额定引入 spring-aspects 依赖并执行其余操作),能够看到引入了两个配置类:AutoProxyRegistrarProxyTransactionManagementConfiguration,这两个类本身代码量都不多,一一查看源码:

public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {private final Log logger = LogFactory.getLog(getClass());

    @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;}
            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) {
                    // 重点在于如下几句代码,尝试注册 AutoProxyCreator
                    AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                    if ((Boolean) proxyTargetClass) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                        return;
                    }
                }
            }
        }
        if (!candidateFound && logger.isInfoEnabled()) {String name = getClass().getSimpleName();
            logger.info(String.format("%s was imported but no annotations were found" +
                    "having both'mode'and'proxyTargetClass'attributes of type" +
                    "AdviceMode and boolean respectively. This means that auto proxy" +
                    "creator registration and configuration may not have occurred as" +
                    "intended, and components may not be proxied as expected. Check to" +
                    "ensure that %s has been @Import'ed on the same class where these "+"annotations are declared; otherwise remove the import of %s "+"altogether.", name, name, name));
        }
    }

}

// ===========================================================

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

    // 事务 Advisor 实现类,援用了前面两个 Bean
    @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;
    }

    // 事务属性解析器,应用的是 AnnotaionTransactionAtributeSource,用于解析 @Transactional 注解的属性
    @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;
    }

}

ProxyTransactionManagementConfiguration引入了事务处理的解析、解决和整体形容相干的 Bean,那么如何让这些 Bean 发挥作用,真正利用到办法中就应该是 AutoProxyRegistrar 所引入的 Bean(严格来说是 Bean Definition)要做的事件。沿着要害代码 AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry) 的调用链始终到最初,能够看到如下代码:

// from org.springframework.aop.config.AopConfigUtils

// 入参 cls 的类对象为 InfrastructureAdvisorAutoProxyCreator
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

    // 查看是否存在固定名称的 BeanDefinition
    if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
        // 如果这个名称的 Bean 的对象类型与入参不同,则依据优先级来判断是否替换对象类型
        // 查看 findPriorityForClass 办法,能够看到返回的是一个 List 的下标,这个 list 的
        // 内容是动态写死的,蕴含了三种类型(见下方代码)。所以能够了解为这是一个逐渐降级
        // 的逻辑,前面将进一步剖析这三个类型
        if (!cls.getName().equals(apcDefinition.getBeanClassName())) {int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
            int requiredPriority = findPriorityForClass(cls);
            if (currentPriority < requiredPriority) {apcDefinition.setBeanClassName(cls.getName());
            }
        }
        return null;
    }

    // 不存在则创立 BD 并注册到 BeanFactory
    RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
    beanDefinition.setSource(source);
    // 留神这个 Bean 的优先级被设为最高
    beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
    beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
    return beanDefinition;
}

/**
 * Stores the auto proxy creator classes in escalation order.
 */
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);
    APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}

在没有其余配置的状况下 InfrastructureAdvisorAutoProxyCreator 将作为 AutoProxyRegistrar 引入的 Bean 的具体类型,查看它的类图如下:

实现的外围接口为SmartInstaniationAwareBeanPostProcessor,它的继承构造阐明了它是一个批改 Bean 的钩子,外围的解决逻辑办法是postProcessAfterInitialization

// from org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator

/**
 * Create a proxy with the configured interceptors if the bean is
 * identified as one to proxy by the subclass.
 * @see #getAdvicesAndAdvisorsForBean
 */
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            // 判断是否须要应用代理来包装
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }
    // 这一步将从获取 BeanFactory 中获取匹配的 Advisor,包含上述的事务 Advisor
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 创立代理
        Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

看到这里基本上就可能明确注解配置的申明式事务是如何失效的了,以 PROXY 模式为例,总结如下:

  1. 应用注解 @EnableTransactionManagement,该注解依据配置的 mode 属性引入了AutoProxyRegistrarProxyTransactionManagementConfiguration两个组件。
  2. AutoProxyRegistrar尝试向容器中增加主动代理生成器(Auto Proxy Creator)的 BeanDefinition,采纳的实现类为 InfrastructureAdvisorAutoProxyCreator。APC 实现了BeanPostProcessor 接口,将在 Bean 实例化后执行代理的生成操作,PC 会尝试从 BeanFactory 中获取实现了 Advisor 接口的 Bean 来作为代理生成的根据。
  3. ProxyTransactionManagementConfiguration是一个配置类,它注册了BeanFactoryTransactionAttributeSourceAdvisor(事务加强 Advisor)、TransactionAttributeSource(事务注解属性解析器)、TransactionInterceptor(事务执行拦截器)三个组件。
  4. TransactionAttributeSource的职能是解析 @Transactional 注解中的属性值并包装为事务相干属性,TransactionInterceptor蕴含了事务的具体执行逻辑。这两个 Bean 作为 BeanFactoryTransactionAttributeSourceAdvisor 的组件由它进行办法调用。
  5. APC 将在 Bean 实例化时依据获取到的事务 Advisor 判断是否须要生成加强代理,如果 Bean 的类或办法上蕴含了 @Transactional 注解,那么将生成蕴含事务拦截器的代理类,实现事务加强。

Spring AOP 原理

其实咱们都晓得申明式事务是 AOP 的子集,是它的利用之一,然而咱们应用 AOP 须要引入 spring-boot-starter-aop,而不引入并不影响咱们应用申明式事务。接下来一探到底 Spring AOP 是如何失效的。

找到 AOP 的主动配置类org.springframework.boot.autoconfigure.aop.AopAutoConfiguration

@Configuration(proxyBeanMethods = false)
// 引入依赖后主动失效,能够通过配置 spring.aop.auto=false 来敞开
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

    // 依赖类 org.aspectj.weaver.Advice,该类属于包 org.aspectj.weaver,并且
    // spring-aop 依赖该包,因而通常这个配置会失效
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(Advice.class)
    static class AspectJAutoProxyingConfiguration {@Configuration(proxyBeanMethods = false)
        // 应用与一般 java config 雷同的注解
        @EnableAspectJAutoProxy(proxyTargetClass = false)
        @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
                matchIfMissing = false)
        static class JdkDynamicAutoProxyConfiguration { }

        @Configuration(proxyBeanMethods = false)
        // 同上, 只是注解的参数不同
        @EnableAspectJAutoProxy(proxyTargetClass = true)
        @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
                matchIfMissing = true)
        static class CglibAutoProxyConfiguration {}}

    // 当 org.aspectj.weaver.Advice 不存在,即短少依赖时作为候补配置项
    // 通常不会进入这个配置块
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnMissingClass("org.aspectj.weaver.Advice")
    @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
            matchIfMissing = true)
    static class ClassProxyingConfiguration {ClassProxyingConfiguration(BeanFactory beanFactory) {if (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
                AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
        }

    }

}

能够看到配置内容和申明式事务十分类似,同样还是以 Java Config 注解 @EnableAspectJAutoProxy 作为入口,也是将注解的 proxy-target-class 裸露到配置文件中。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

    // 是否采纳 CGLIB 作为代理实现
    boolean proxyTargetClass() default false;

    // 是否将代理本身裸露到 ThreadLocal 环境以便在拦截器中可能获取到代理自身
    boolean exposeProxy() default false;}

还是同样的配方,应用了 @Import 注解引入组件,然而数量略有缩小,只有一个名为 AspectJAutoProxyRegistrar 的工具类。

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

    // 注册 Bean Definition
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        // 注册 AutoProxyCreator,这里应用实现类是 AnnotationAwareAspectJAutoProxyCreator
        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

        // 依据注解 @EnableAspectJAutoProxy 上的参数批改 BD
        AnnotationAttributes enableAspectJAutoProxy =
                AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        if (enableAspectJAutoProxy != null) {if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }

}

很显著起作用的还是增加 Aspect Proxy Creator 相干的 Bean Definition,根据上述的优先级 AnnotationAwareAspectJAutoProxyCreator 将会笼罩InfrastructureAdvisorAutoProxyCreator。这几个候选 APC 的继承关系如下图所示:

比照一下 InfrastructureAdvisorAutoProxyCreatorAspectJAwareAdvisorAutoProxyCreator这两个同级的类别离笼罩了哪些办法:

public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {

    @Nullable
    private ConfigurableListableBeanFactory beanFactory;

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

    // 这个办法最终被 org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
    // 所应用,即限度只有框架自身的 Advisor 可能失效
    @Override
    protected boolean isEligibleAdvisorBean(String beanName) {return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&
                this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
    }

}

// ===========================================================

public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {private static final Comparator<Advisor> DEFAULT_PRECEDENCE_COMPARATOR = new AspectJPrecedenceComparator();

    // 笼罩了 Advisor 排序办法,实质起因是须要对源自对立个 Aspect 的 Advisor 进行进一步排序
    // 这排序还挺简单的,利用了偏序排序,具体规定请查看该办法的 javadoc
    @Override
    protected List<Advisor> sortAdvisors(List<Advisor> advisors) {List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = new ArrayList<>(advisors.size());
        for (Advisor advisor : advisors) {
            partiallyComparableAdvisors.add(new PartiallyComparableAdvisorHolder(advisor, DEFAULT_PRECEDENCE_COMPARATOR));
        }
        List<PartiallyComparableAdvisorHolder> sorted = PartialOrder.sort(partiallyComparableAdvisors);
        if (sorted != null) {List<Advisor> result = new ArrayList<>(advisors.size());
            for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {result.add(pcAdvisor.getAdvisor());
            }
            return result;
        }
        else {return super.sortAdvisors(advisors);
        }
    }

    // 增加一个裸露 AspectJ 调用 (MethodInvocation) 的前置 Advisor,也是利用 ThreadLocal
    @Override
    protected void extendAdvisors(List<Advisor> candidateAdvisors) {AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
    }

    // 作为 Aspect 自身的 Bean 不能被代理
    @Override
    protected boolean shouldSkip(Class<?> beanClass, String beanName) {
        // TODO: Consider optimization by caching the list of the aspect names
        List<Advisor> candidateAdvisors = findCandidateAdvisors();
        for (Advisor advisor : candidateAdvisors) {
            if (advisor instanceof AspectJPointcutAdvisor &&
                    ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {return true;}
        }
        return super.shouldSkip(beanClass, beanName);
    }

    // 用于排序的辅助类
    private static class PartiallyComparableAdvisorHolder implements PartialComparable {// ...}

}

能够看到两者并没有进行核心内容上的更改,都是针对各自利用场景的修补,InfrastructureAdvisorAutoProxyCreator只为框架自身的工具服务,而 AspectJAwareAdvisorAutoProxyCreator 增加了一些针对 AspectJ 申明切面的解决逻辑,所以实质上两者还是保持一致的。AspectJAwareAdvisorAutoProxyCreator并没有创立 Advisor 的相干逻辑,而 EnableAspectJAutoProxy 只引入这一个工具,能够猜想到依据注解解析 Advisor 的内容蕴含在它的子类 AnnotationAwareAspectJAutoProxyCreator 中,疏忽一些非次要代码展现如下:

public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {

    @Nullable
    private List<Pattern> includePatterns;

    @Nullable
    private AspectJAdvisorFactory aspectJAdvisorFactory;

    @Nullable
    private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder;

    // 疏忽一些非次要代码 ...

    @Override
    protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {super.initBeanFactory(beanFactory);
        // 创立 advisor factory
        if (this.aspectJAdvisorFactory == null) {this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
        }
        // 创立 advisor builder
        this.aspectJAdvisorsBuilder =
                new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
    }

    @Override
    protected List<Advisor> findCandidateAdvisors() {
        // 父类逻辑调用
        List<Advisor> advisors = super.findCandidateAdvisors();
        // 这里将依据 aspectj 注解解析生成额定的 advisor
        if (this.aspectJAdvisorsBuilder != null) {advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        }
        return advisors;
    }
    
    // 疏忽一些非次要代码 ...

}

正如这个类的名称AnnotationAwareAspectJAutoProxyCreator,它增加了对 aspectj 注解(@Aspect@PointCut@Before 等等)的反对。Spring AOP 失效逻辑总结如下:

  1. 应用注解@EnableAspectJAutoProxy,由它引入AspectJAutoProxyRegistrar,开启对 Java 注解申明式 AOP 的反对
  2. AspectJAutoProxyRegistrar向容器中增加 AnnotationAwareAspectJAutoProxyCreator 作为 APC 的实现类,它将笼罩其余 APC(如果存在)
  3. AnnotationAwareAspectJAutoProxyCreator除了对实现了 Advisor 接口的 Bean 的解决之外,同时会判断 Bean 是否蕴含了 aspectj 相干的注解,并依据这些注解生成对应的 Advisor
  4. APC 将在 Bean 实例化时依据获取到的 Advisor 判断是否须要生成加强代理
  5. 三种候选 APC 优先级顺次进步,别离对应不同的场景:

    1. InfrastructureAdvisorAutoProxyCreator:对应一些外部框架性能实现的反对,例如申明式事务、申明式缓存等
    2. AspectJAwareAdvisorAutoProxyCreator:对应 XML 配置场景下的 AOP 申明反对(所以它不间接蕴含对于切面定义的解决)
    3. AnnotationAwareAspectJAutoProxyCreator:对应 Java Config 配置场景下注解式 AOP 申明的反对

切入程序解析

当业务性能逐渐减少,可能会退出各种各样的切面逻辑,这种状况下就须要额定关注切入的程序,程序不对可能会造成重大的问题。接下来顺着代码看看 Spring AOP 对于切面程序是如何解决的。

通过下面的剖析,咱们能够从 AbstractAutoProxyCreator 的 postProcessAfterInitialization 办法进入:

// ========= AbstractAutoProxyCreator =========
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            // 进入这个办法外部
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }
    // 很显著这一步在获取切面,返回的数组中内容的程序即代表了切面的程序
    // 这个办法在该类中为形象办法,由子类笼罩实现。由此处持续往下走
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);
        Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

// ========= AbstractAdvisorAutoProxyCreator =========

@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
    // 持续往下走
    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    // 这里对返回值做了一些解决
    if (advisors.isEmpty()) {return DO_NOT_PROXY; // 如果没有,返回 null}
    return advisors.toArray();}

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    // 这一步将获取所有候选的 Advisor
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 遍历候选的 Advisor 筛选出其中与 Bean 相匹配的
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    // 本类中为空办法,AspectJAwareAdvisorAutoProxyCreator 对其进行了笼罩
    // 增加了一个裸露 AOP 调用的 advisor,这个 advisor 的 order 值为 PriorityOrdered.HIGHEST_PRECEDENCE + 1 
    extendAdvisors(eligibleAdvisors);
    // 对 advisor 进行排序,进入上面的办法,查看是如何排序的
    // 这一步不同的 APC 会有不同的实现,然而也是属于扩大的关系
    if (!eligibleAdvisors.isEmpty()) {eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

// AbstractAdvisorAutoProxyCreator 的默认实现
protected List<Advisor> sortAdvisors(List<Advisor> advisors) {// 外部调用的是 List.sort(AnnotationAwareOrderComparator.INSTANCE)
    AnnotationAwareOrderComparator.sort(advisors);
    return advisors;
}

// AspectJAwareAdvisorAutoProxyCreator 的笼罩实现
protected List<Advisor> sortAdvisors(List<Advisor> advisors) {List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = new ArrayList<>(advisors.size());
    // 这里把所有的 advisor 都包装成为 PartiallyComparableAdvisorHolder
    // DEFAULT_PRECEDENCE_COMPARATOR 的类型为 AspectJPrecedenceComparator
    // 而这个类型外部同样蕴含了一个 AnnotationAwareOrderComparator
    for (Advisor advisor : advisors) {
        partiallyComparableAdvisors.add(new PartiallyComparableAdvisorHolder(advisor, DEFAULT_PRECEDENCE_COMPARATOR));
    }
    // 应用偏序排序,偏序排序属于离散数学领域,自己也不是特地分明
    // 应用这种排序次要是为了解决同一个切面中申明的 advice
    List<PartiallyComparableAdvisorHolder> sorted = PartialOrder.sort(partiallyComparableAdvisors);
    if (sorted != null) {List<Advisor> result = new ArrayList<>(advisors.size());
        for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {result.add(pcAdvisor.getAdvisor());
        }
        return result;
    }
    else {return super.sortAdvisors(advisors);
    }
}

所以不同的切面之间都是应用 AnnotationAwareOrderComparator 来确定程序,该类继承自 OrderComparator,减少了对 Spring 注解@Order 和 J2EE 注解 @Priority 的反对。它的比拟的逻辑能够总结如下:

  1. 如果实现了 Ordered 接口则应用 Ordered.getOrder()办法获取排序值
  2. 如果没有实现 Ordered 接口,查找类对象是否有增加两种反对的注解(包含继承关系),如果找到注解则应用注解的属性值作为排序值
  3. 如果都没有,排序值取 Ordered.LOWEST_PRECEDENCE(2147483647)
  4. 如果两者只有一方实现了 PriorityOrdered 接口,那么实现方优先级更高,否则依据排序值比拟
  5. 排序值越大,优先级越低

而对于同一个切面中的 advice 来说,就须要应用额定的判断,这部分说实话不是特地明确,有趣味能够深刻一下源码,这里就翻译一下 AspectJAwareAdvisorAutoProxyCreator#sortAdvisors 办法的 javadoc 吧:

依据 aspectj 优先级对提供的 advisor 实例进行排序。如果两个 advice 来自同一个 advisor,那么它们的程序是一样的。同一个 advisor 的 advice 将应用如下规定进一步排序:如果任意一方是 ’After’ 类型的 advice,那么后申明的优先级最高(即最初运行),否则先申明的优先级最高(即最先运行)。

这其实也是合乎常识逻辑的排序,即先申明的先执行,然而因为切面的构造,在出方向上优先级最高的最初执行,所以最初申明的 ’After’ 类型的 advice 因为优先级最高最初执行。

原始程序

那么在排序值雷同的状况下,不同 advice 的同类型的 advice 如何确定程序呢?咱们能够看到执行 advice 之间排序的 AbstractAdvisorAutoProxyCreator.sortAdvisors 这个办法最终会应用 List.sort(Comparator)来执行排序,查看该办法的 javadoc 能够得悉应用的排序实现是从 MergeSort 优化而来的 TimSort,它是一种稳固排序算法,因而能够推断出如果排序值雷同,那么程序就取决于他们之间原来的程序。从新追溯回到原始程序的源头:

// ========= AbstractAdvisorAutoProxyCreator =========
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    // 这一步获取原始 Advisor 列表,往里面走
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

// 该办法被子类 AnnotationAwareAspectJAutoProxyCreator 重写
protected List<Advisor> findCandidateAdvisors() {Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
    // 应用工具类来获取,持续往里走
    return this.advisorRetrievalHelper.findAdvisorBeans();}

// AnnotationAwareAspectJAutoProxyCreator 重写的 findCandidateAdvisors
@Override
protected List<Advisor> findCandidateAdvisors() {
    // 调用父类办法
    List<Advisor> advisors = super.findCandidateAdvisors();
    // 结构依据注解申明的对应的 advisor
    if (this.aspectJAdvisorsBuilder != null) {advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    return advisors;
}

// ========= AbstractAdvisorAutoProxyCreator =========

public List<Advisor> findAdvisorBeans() {
    // 获取所有实现了 Advisor 接口的 Bean 名称,同时做了缓存解决
    String[] advisorNames = this.cachedAdvisorBeanNames;
    if (advisorNames == null) {
        // 获取相干的 Bean 名称,进入此办法持续走
        advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false);
        this.cachedAdvisorBeanNames = advisorNames;
    }
    if (advisorNames.length == 0) {return new ArrayList<>();
    }

    List<Advisor> advisors = new ArrayList<>();
    // 依照获取到的 Bean 名称一一增加到 List 中
    for (String name : advisorNames) {if (isEligibleBean(name)) {if (this.beanFactory.isCurrentlyInCreation(name)) {if (logger.isTraceEnabled()) {logger.trace("Skipping currently created advisor'" + name + "'");
                }
            }
            else {
                try {advisors.add(this.beanFactory.getBean(name, Advisor.class));
                }
                catch (BeanCreationException ex) {// 一些初始化相干的代码 ...}
            }
        }
    }
    return advisors;
}

由下面的代码可知,Advisor 的原始程序取决于 BeanFactory 取出相干 Bean 名称的程序,同时由注解形容构建出的 Advisor 全部排在原生 Advisor 实现类的前面。具体到 SpringBoot 的利用场景下,最初执行的内容为 DefaultListableBeanFactory 下的办法:

private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {List<String> result = new ArrayList<>();

    // 依据 beanDefinitionNames 这个 list 成员进行遍历
    for (String beanName : this.beanDefinitionNames) {if (!isAlias(beanName)) {
            try {RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                // Only check bean definition if it is complete.
                if (!mbd.isAbstract() && (allowEagerInit ||
                        (mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
                                !requiresEagerInitForType(mbd.getFactoryBeanName()))) {
                    // 省略匹配逻辑校验代码 ...
                    if (matchFound) {result.add(beanName);
                    }
                }
            }
            // 省略异样解决代码 ...
        }
    }

    // 依据 manualSingletonNames 这个 list 成员遍历
    // 这里次要蕴含一些手动管制、无需解决 Bean 生命周期的单例,比方 SpringBootBanner
    // 通常 Advisor 实现类不会呈现在这里
    for (String beanName : this.manualSingletonNames) {
        try {
            // 省略代码... 

            if (isTypeMatch(beanName, type)) {result.add(beanName);
            }
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Shouldn't happen - probably a result of circular reference resolution...
            logger.trace(LogMessage.format("Failed to check manually registered singleton with name'%s'", beanName), ex);
        }
    }

    return StringUtils.toStringArray(result);
}

最终咱们能够看到原始数据的程序来源于 BeanFactory 的 beanDefinitionNames 这个 List<String> 类型的成员,这个汇合蕴含了所有注册的 Bean 名称,并且维持了 Bean 注册的程序,Bean 注册的细节此处就不开展了,咱们能够间接在上述办法打断点调试,依据 SpringBoot 运行调试后果能够看出如下几点规定:

  1. 6 个内置的 Bean 和 SpringBoot 启动类最先注册,内置 Bean 包含internalConfigurationAnnotationProcessorinternalAutowiredAnnotationProcessorinternalCommonAnnotationProcessorinternalEventListenerProcessorinternalEventListenerFactoryinternalCachingMetadataReaderFactory
  2. 接下来依据扫包获取利用代码中申明的 Bean,扫包程序通常是依照全类名的字母序(包含 @Configuration 润饰的配置类,但不包含其中定义的 Bean)
  3. 而后是利用代码中引入的 Bean,包含配置类下申明的 Bean 以及 Import 引入的 Bean
  4. 最初是 SpringBoot 主动配置类相干的内容

总结

Spring AOP 的外围类是 AutoProxyCreator,它作为钩子工具在 Bean 实例化时执行了代理创立操作,这也再一次表明 Spring AOP 在默认的 proxy 模式下应用的是动静代理,Spring 只是借用了 AspectJ 的一些切面形容的注解,并没有应用依赖非凡编译器的动态织入。

切面的程序是一个必须思考的问题,Spring 次要通过 org.springframework.core.Ordered 接口以及 org.springframework.core.annotation.Order 注解(还包含 j2ee 的 Priority 注解)来申明排序值以管制程序。在 SpringBoot 应用环境下,您须要额定留神几点:

  1. 开启申明式事务的注解 @EnableTransactionManagement 蕴含在主动配置类中,并没有将 order 属性间接裸露到配置文件中,其默认的程序值为 Ordered.LOWEST_PRECEDENCE 即最低程序。如果必须要配置,能够手动在利用配置类上被动应用 @EnableTransactionManagement 并批改 order 属性值,然而这会让配置文件中的一些相干配置生效。
  2. 同时应用申明式事务和申明式缓存并且不批改 order 值,因为申明式缓存须要手动增加@EnableCaching,这使得默认状况下缓存 Advisor 的原始程序高于事务 Advisor,因而先切面的入口处先执行缓存逻辑再执行事务逻辑,这恰好满足个别的应用常理。
  3. 在开启 Spring AOP 应用 aspectj 注解申明切面时,如果不指定 Order 程序值,那么默认程序值为最低程序,依据原始程序的逻辑,构建进去的切面全副位于原生切面的前面,也就是排在事务等框架提供的逻辑之后,您须要确保这是没问题的,否则请显式指定程序值。
  4. 不同的切面举荐放在不同的类中并指定程序值,避免意想不到的后果产生。
正文完
 0