【一】Spring AOP 最全源码详解之AOP元数据解析

本文详细解析了Spring AOP在bean创建过程中如何进行元数据解析,包括findCandidateAdvisors方法寻找和解析advisor,buildAspectJAdvisors构建AspectJ顾问,以及MetadataAwareAspectInstanceFactory对象创建和获取Advisor的详细步骤。通过对切点、连接点、通知等AOP参数的封装,展示了Spring AOP如何为后续bean初始化做好代理准备。
摘要由CSDN通过智能技术生成

目录

1.  findCandidateAdvisors

2. buildAspectJAdvisors

2.1. 创建一个MetadataAwareAspectInstanceFactory对象

2.2. getAdvisors(factory)

2.3 getAdvice

3. 附录:本工程项目文件


bean创建过程中,在createBean步骤的resolveBeforeInstantiation中会调用beanPostProcessor处理器执行各自的postProcessBeforeInstantiation方法。在Spring在引入了AOP的情况下,后置处理器会多出一个AnnotationAwareAspectJAutoProxyCreator。在创建bean进行到该步骤的时候,该beanPostProcessor会在postProcessBeforeInstantiation方法中进行代理类Pointcut,JointPoint,Advice,Advisor的解析和缓存。为后续初始化bean中实现bean的代理做好准备。

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
            if (result != null) {
                return result;
            }
        }
    }
    return null;
}

直接来看调用ibp.postProcessBeforeInstantiation(beanClass, beanName)的实现方法, 

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    // 如果是普通bean,则返回beanName,如果是FactoryBean,则返回加上前缀&的&beanName
    Object cacheKey = getCacheKey(beanClass, beanName);

    // 第一次进入时,targetSourcedBeans还未缓存有对象,故会进入。
    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        // 如果this.advisedBeans有缓存值,说明该bean已经被解析过了,直接返回null就跳过了后续的解析
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        // 基础类不应该被代理
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }
    // 如果用户自定义了TargetSource,那么直接返回用户自定义的代理类。否则返回null,使得Spring框架能继续执行下去。
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }
    return null;
}

首先getCacheKey是获取beanName,如果是FactoryBean,那么beanName是要加上前缀"&"。第一次进入时,if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName))肯定是会进入的。如果advisedBeans有缓存值,说明该bean已经被解析过了,直接返回null就跳过了后续的解析,否则进入第二个if分支。第一个条件isInfrastructureClass()是判断当前bean类型是否是基础类型,如果是则不会被代理。基础类型有Advice.class,Pointcut.class, Advisor.class, AopInfrastructureBean.class这4种。关键的核心代码是在shouldSkip(beanClass, beanName)中,返回的结果用于判断是否要跳过解析。但是执行的过程却远远不是一句话能说明白的,我们一起深入剖析shouldSkip方法。(后续的getCustomTargetSource方法是返回用户自定义的代理类。如果没有定义就返回null,使得Spring框架能继续执行下去。这里后续不再分析~)

protected boolean shouldSkip(Class<?> beanClass, String beanName) {
    // findCandidateAdvisors最终会由BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans执行
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 找到的candidate中有beanName与AspectJPointcutAdvisor相同,也就是PointcutAdvisor的实现类,则不会进行作为代理的尝试。
    for (Advisor advisor : candidateAdvisors) {
        if (advisor instanceof AspectJPointcutAdvisor &&
                ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
            return true;
        }
    }
    // 根据ORIGINAL_INSTANCE_SUFFIX判断给定bean名称是“原始实例”类型,如果是就跳过代理的尝试。
    return super.shouldSkip(beanClass, beanName);
}

核心的步骤是findCandidateAdvisors,用于寻找和解析advisor。然后再找到的advisor们中判断是否可以跳过。有两种情况可以被跳过:1.AspectName刚好就是这个bean的name;2.这个bean是原始实例,原始bean的后缀有“.ORIGINAL”标志。

接下来我们进入核心的findCandidateAdvisors方法分析:

protected List<Advisor> findCandidateAdvisors() {
    List<Advisor> advisors = super.findCandidateAdvisors();
    // 合并全局的advisors后返回
    if (this.aspectJAdvisorsBuilder != null) {
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    return advisors;
}

1.  findCandidateAdvisors

super.findCandidateAdvisors()会借助BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans执行,我们直接来看findAdvisorBeans。

public List<Advisor> findAdvisorBeans() {
    String[] advisorNames = this.cachedAdvisorBeanNames;
    if (advisorNames == null) {
        // 从bean工厂中寻找Advisor.class,并且是单例类型的beanName
        advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                this.beanFactory, Advisor.class, true, false);
        this.cachedAdvisorBeanNames = advisorNames;
    }
    if (advisorNames.length == 0) {
        return new ArrayList<>();
    }

    List<Advisor> advisors = new ArrayList<>();
    for (String name : advisorNames) {
        if (isEligibleBean(name)) {
            if (this.beanFactory.is
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值