美文网首页
AOP源码分析之AnnotationAwareAspectJAu

AOP源码分析之AnnotationAwareAspectJAu

作者: 会上树的程序猿 | 来源:发表于2020-05-27 21:20 被阅读0次

上节我们通过注解@EnableAspectJAutoProxy作为Aop源码分析的入口,最后发现做了那么多工作仅仅是把AnnotationAwareAspectJAutoProxyCreator这个后置处理器注册和创建并进行添加操作,为啥说AnnotationAwareAspectJAutoProxyCreator是一个后置处理器,可以通过它的继承实现关系来发现如下图所示:

AnnotationAwareAspectJAutoProxyCreator.png

从它的家族类图不难发现AnnotationAwareAspectJAutoProxyCreator 是一个InstantiationAwareBeanPostProcessor类型的后置处理器,既然前面我们分析它的创建和注册过程,本节来看看在Aop中是如何用到它的,同样我们还是 以我们的测试类作为入口进行分析,测试代码如下:

 //Aop测试
@Test
public void testAop(){
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAop.class);
    MathCalculator calculator = applicationContext.getBean(MathCalculator.class);
    calculator.div(10,5);

    applicationContext.close();
}

分析的入口还是以我们AnnotationConfigApplicationContext容器的创建作为分析入口,跟踪代码来到:

 public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    this();
    this.register(componentClasses);
    this.refresh();
}

首先Dbug来到了AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(...)构造方法,其中核心的是 this.refresh()方法,此方法的作用之前也已经提到过了,继续跟踪代码来到此方法,其中如下的代码片段值得我们注意:

this.finishBeanFactoryInitialization(beanFactory);

这段代码主要的目的是完成我们beanFactory的初始化工作和创建剩下未创建的单实例bean(这里也就是我们自己的bean),继续跟踪代码来到:

首先一进方法对我们的beanFactory进行判断,具体如下:

 if (beanFactory.containsBean("conversionService") && beanFactory.isTypeMatch("conversionService", ConversionService.class)) {
        beanFactory.setConversionService((ConversionService)beanFactory.getBean("conversionService", ConversionService.class));
    }
  • 上述是判断容器中是否id为conversionService 的bean ,其他的都是类似的操作这里不在一一仔细看了,继续跟踪代码来到如下的代码片段:
beanFactory.freezeConfiguration();

这段代码的意思是,将我们的 bean的定义的元信息进行缓存,不在做进一步的变化,跟踪代码来到DefaultListableBeanFactory类中:

private volatile String[] frozenBeanDefinitionNames;

  public void freezeConfiguration() {
    this.configurationFrozen = true;
    this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
}
Aop源码分析1.png

接着我们来到如下的代码片段:

beanFactory.preInstantiateSingletons();

上述这段代码主要的目的是初始化剩下的单实例bean,跟踪代码来到:

 List<String> beanNames = new ArrayList(this.beanDefinitionNames);

首先从beanDefinitionNames中获取所有的bean的definition信息,接着是循环创建每一个bean

image.png

获取到bean的definition 信息之后进行while循环处理,跟踪代码会发现其实质做了如下的判断处理:

  • bean的定义是否抽象,是否不是单例的,是否是懒加载的。

  • 通过如下代码来判断bean是否是一个BeanFactory类型的bean

  if (this.isFactoryBean(beanName)) {
                    bean = this.getBean("&" + beanName);
                    break;
                }

如果不是工厂Bean的话,通过this.getBean(beanName)来创建bean,继续跟踪代码来到类AbstractFactory类中:

public Object getBean(String name) throws BeansException {
    return this.doGetBean(name, (Class)null, (Object[])null, false);
}

继续跟踪代码来到#doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)方法:

  • 首先通过如下代码来获取当前要创建bean的name值
String beanName = this.transformedBeanName(name);
  • 接着是通过如下代码从缓存中通过beanName去获取单实例bean,如果能获取到则说明该beanBean之前被创建过(所有创建过的单实例Bean都会被缓存起来)
  Object sharedInstance = this.getSingleton(beanName);

这里分为两种情况,如果从缓存拿到了当前要创建的bean,直接返回到方法上一层继续循环遍历下一个待创建的bean,这里我截个没有创建的bean的图来走下后面的创建流程:

image.png

图中所显示的bean我们发现从缓存中没有获取到,那我们继续跟踪代码来到:

  • 跟踪代码发下期间通过如下代码来检查bean 的定义信息是否在父BeanFactory中存在,如果存在的话,调用对应工厂Bean的方法去创建bean对象
 BeanFactory parentBeanFactory = this.getParentBeanFactory();
        if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
            String nameToLookup = this.originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
            }
...已省略.....
  • 通过下面的操作来标记当前bean已经被创建过了
if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }
  • 通过如下的操作来处理bean与bean之间依赖的问题
    • 1.首先获取当前bean的定义信息
RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
  • 2.通过如下操作来先获取当前bean所依赖的其他bean组件,如果存在依赖的bean的话,通过getBean(...)进行依赖bean组件的创建
 RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
            this.checkMergedBeanDefinition(mbd, beanName, args);
            String[] dependsOn = mbd.getDependsOn();
            String[] var11;
            if (dependsOn != null) {
                var11 = dependsOn;
                int var12 = dependsOn.length;

                for(int var13 = 0; var13 < var12; ++var13) {
                    String dep = var11[var13];
                    if (this.isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }

                    this.registerDependentBean(dep, beanName);

                    try {
                        this.getBean(dep);
                    } catch (NoSuchBeanDefinitionException var24) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", var24);
                    }
                }
            }
  • 接下来是真正的创建过程:
this.createBean(beanName, mbd, args);

继续跟踪代码来到AbstractAutowireCapableBeanFactory类中的#createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)方法,具体来看如下分析:

image.png

其中上图中所示的是方法的参数 mbd参数为bean的定义的信息

  • 期间通过如下代码片段操作:
beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);

通过方法#resolveBeforeInstantiation(beanName, mbdToUse)的拦截,让BeanPostProcessor【后置处理器】尝试着返回一个代理对象,继续跟踪代码来到:

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
            Class<?> targetType = this.determineTargetType(beanName, mbd);
            if (targetType != null) {
                bean = this.applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    bean = this.applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }

        mbd.beforeInstantiationResolved = bean != null;
    }

    return bean;
}
  • 首先在此方法中我们的InstantiationAwareBeanPostProcessor后置处理器先执行了

  • 接着进入if语句执行我们的

bean = this.applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);

进去方法来到:

 protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    Iterator var3 = this.getBeanPostProcessors().iterator();

    while(var3.hasNext()) {
        BeanPostProcessor bp = (BeanPostProcessor)var3.next();
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
            Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
            if (result != null) {
                return result;
            }
        }
    }

    return null;
}

获取所有的BeanPostProcessor接着遍历处理类型是InstantiationAwareBeanPostProcessor的后置处理器然后调用它的#postProcessBeforeInstantiation(...)方法具体去处理,至于处理的逻辑这里不在细看,继续跟踪代码来到:

  if (beanInstance != null) {
            return beanInstance;
        }

如果没有获取代理对象,那么进行对象的真正创建过程:

beanInstance = this.doCreateBean(beanName, mbdToUse, args);

创建过程的细节,在上一篇中我们已经详细的说过了,这里不在累赘,其实到这里我们本篇的核心已经说完了,不知还记得开篇的那张类的依赖关系图,我们说了AnnotationAwareAspectJAutoProxyCreator实质是一个InstantiationAwareBeanPostProcessor类型的后置处理器,通过我们一步步的Dbug发现,在我们的每一个Bean的创建之前都会调用InstantiationAwareBeanPostProcessor类型的#postProcessBeforeInstantiation(...)方法进行相关的处理操作,既然知道了AnnotationAwareAspectJAutoProxyCreator的作用,那么在下节我们来分析#postProcessBeforeInstantiation(...)调用此方法具体做了什么?

相关文章

  • AOP源码分析之AnnotationAwareAspectJAu

    上节我们通过注解@EnableAspectJAutoProxy作为Aop源码分析的入口,最后发现做了那么多工作仅仅...

  • IOS中AOP框架Aspects源码分析

    IOS中AOP框架Aspects源码分析 AOP是Aspect Oriented Programming的缩写,意...

  • 2018-05-19

    spring源码分析(五) 目录五、源码分析--5.6、Spring AOP 设计原理及具体实践----5.6.1...

  • spring-aop 2.筛选通知器

    1.前言 从本篇文章开始,我将会对 Spring AOP 部分的源码进行分析。本文是 Spring AOP 源码分...

  • 基于注解的SpringAOP源码解析(三)

    注意,读完本篇文章需要很长很长时间 在之前的2篇文章:AOP源码分析(一)AOP源码分析(二)中,我们搭建了Spr...

  • Spring源码分析之AOP

    AOP(Aspect Oriented Programing),即面向切面编程。它的主要思想是将分散在各个业务逻辑...

  • Spring源码分析之AOP

    作者: 一字马胡 转载标志 【2018-01-02】 更新日志 前言 本文是Spring源码分析系列的第三篇文章...

  • spring源码分析之AOP

    AOP核心概念 横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点切面(aspect):类...

  • AOP源码分析之@EnableAspectJAutoProxy

    上节我们在Spring注解驱动开发AOP功能的篇幅中简单的通过案例来回顾了AOP的注解驱动开发的基本过程,同时也提...

  • Spring源码分析之AOP

    AOP是什么 面向切面的程序设计(Aspect-oriented programming,AOP,又译作面向方面的...

网友评论

      本文标题:AOP源码分析之AnnotationAwareAspectJAu

      本文链接:https://www.haomeiwen.com/subject/hmiiahtx.html