SpringAOP源码跟踪及学习

Spring 版本 4.3.2

在拿到 Bean 实例以后,会经历一系列的初始化工作,如:工厂回调、init 方法、后处理器在 Bean 初始化前后的处理等,在一般情况下(非 factory-method 创建的 Bean 等),AOP代理对象的创建就在后处理器的处理方法中实现。

入口

以 AbstractAutowireCapableBeanFactory 类中的 initializeBean 方法作为起始点进行跟踪

/**
* Initialize the given bean instance, applying factory callbacks
* as well as init methods and bean post processors.
* <p>Called from {@link #createBean} for traditionally defined beans,
* and from {@link #initializeBean} for existing bean instances.
*
* 初始化给定的 bean 实例,应用工厂回调方法以及 init 方法和 bean 的后处理器。
* 该方法会被传统定义 bean 的 createBean 方法所调用,也会被重载方法所引用
*/
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        
        // 后处理器的前调用
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
        
        // 初始化后,进行后处理器的后调用,跟踪此方法
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

依然在 AbstractAutowireCapableBeanFactory 类中。

拿到 BeanFactory 中所有针对 Bean 的后处理器集合,依次调用。

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
    throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        
        // 利用处理器的处理方法,对 bean 实例进行处理,并返回一个对象
        Object current = processor.postProcessAfterInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

注册创建器

在后处理器集合中,有一个处理器叫做 AnnotationAwareAspectJAutoProxyCreator 创建器,该处理器在解析<aop:config>标签、或者解析相关注解时被注册到工厂中,如下:

// 如果必要的话注册AspectJ自动代理创建器
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {

    // 传递了 AspectJAwareAdvisorAutoProxyCreator 的 Class,进入这个方法
    return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}


private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

    //工厂中是否已经注册了 org.springframework.aop.config.internalAutoProxyCreator
    if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
        BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);

        //如果已经有注册了 internalAutoProxyCreator,并且和入参传递的Class不是同一个Class,
        //那么就根据优先级进行选择
        if (!cls.getName().equals(apcDefinition.getBeanClassName())) {

            //类 AopConfigUtils 中有个 ArrayList 属性 APC_PRIORITY_LIST,在类静态构造中依次加入了
            //几个创建器,这个方法就是查找某个创建器在 APC_PRIORITY_LIST 中的索引,如果没有找到就报错
            int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
            int requiredPriority = findPriorityForClass(cls);

            // internalAutoProxyCreator 的索引为0,入参的 AspectJAwareAdvisorAutoProxyCreator
            // 索引为1,后者要大,所以重新设置下 apcDefinition 的 beanClass
            if (currentPriority < requiredPriority) {
                apcDefinition.setBeanClassName(cls.getName());
            }
        }

        //直接返回null
        return null;
    }
    
    // 如果没有注册 internalAutoProxyCreator ,组装一个 Bean Definition,以 
    // AspectJAwareAdvisorAutoProxyCreator 作为 bean Class,然后注册到工厂中
    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;
}

从上面可以看见创建器 AnnotationAwareAspectJAutoProxyCreator 的注册经过,Bean Definition 是对 Bean 的描述,创建 bean 对象时,会以 Bean Definition 为依据进行实例化和初始化。

postProcessAfterInitialization

查看创建器的处理方法postProcessAfterInitialization

该方法在创建器的超类 AbstractAutoProxyCreator 中实现

/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* 
* 如果 bean 被定义为子类代理,则使用已配置的拦截器创建代理
*/
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (!this.earlyProxyReferences.contains(cacheKey)) {
            
            // 缓存中没有的情况
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

/**
* Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
* 
* 必要的话包装给定的 bean,即,他有资格被代理
*/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    
    // advisedBeans 存放 bean 是否可以被代理的信息,作为缓存,避免重复判断
    // Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        
        // 如果 bean 是一些特殊的类,比如 Pointcut/Advisor,又或者没有 @Aspect 注解等
        // 这些 bean 不应该被代理,信息存放到 advisedBeans 集合中
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // Create proxy if we have advice.
    // 如果有通知,创建代理
    
    // 拿到所有匹配该 bean 的通知,如果使用了切入点表达式或者 AspectJ 风格的增强,
    // 还需要在通知链的开始处添加 ExposeInvocationInterceptor 拦截器
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        
        // 通知链不为null,可以代理
        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;
}

创建代理

该方法在 AbstractAutoProxyCreator 中实现

/**
* Create an AOP proxy for the given bean.
* 
* 为指定的 bean 创建一个 AOP 代理
*/
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
                             @Nullable Object[] specificInterceptors, TargetSource targetSource) {

    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        
        // 在 beanFactory 中,beanName 有对应的 BeanDefinition,此方法就是为 BeanDefinition 的
        // attributes 属性添加键值对,key 为 xxx.originalTargetClass , value 包含了 beanClass
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }

    ProxyFactory proxyFactory = new ProxyFactory();
    
    // 将创建器中的一些属性拷贝到新创建的代理工厂
    proxyFactory.copyFrom(this);

    // proxyTargetClass 属性对代理方式的确定有非常大的影响
    // 当从创建器中拷贝的属性 proxyFactory 为 false 时,下面的两个方法需要详细跟踪
    if (!proxyFactory.isProxyTargetClass()) {
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        }
        else {
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }

    // 对拦截器或者通知进行包装,包装成Advisor对象
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    
    // 在代理工厂中添加 Advisor 通知链
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    
    // 子类中如果没有覆盖,那么此方法为空实现
    customizeProxyFactory(proxyFactory);

    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    // 通过代理工厂获取代理
    return proxyFactory.getProxy(getProxyClassLoader());
}

proxyTargetClass 布尔属性值的确定对代理方式有着非常大的影响。

当配置了<aop:aspectj-autoproxy>,使用注解方式时;又或者是使用xml配置<aop:config>时,两个标签都具有的proxy-target-class属性默认为 false

那么上述步骤创建 ProxyFactory 对象时,从创建器中拷贝的 proxyTargetClass 属性则为 false,进入条件

if (!proxyFactory.isProxyTargetClass()) {
    if (shouldProxyTargetClass(beanClass, beanName)) {
        proxyFactory.setProxyTargetClass(true);
    }
    else {
        evaluateProxyInterfaces(beanClass, proxyFactory);
    }
}

先看第一个方法shouldProxyTargetClass

shouldProxyTargetClass

该方法在 AbstractAutoProxyCreator 中实现

/**
* Determine whether the given bean should be proxied with its target class rather than its interfaces.
* <p>Checks the {@link AutoProxyUtils#PRESERVE_TARGET_CLASS_ATTRIBUTE "preserveTargetClass" attribute}
* of the corresponding bean definition.
* 
* 确定给定的bean是否应该使用其目标类而不是其接口进行代理。
* 检查对应 bean definition 的 preserveTargetClass 属性。
*/
protected boolean shouldProxyTargetClass(Class<?> beanClass, String beanName) {
    
    return (this.beanFactory instanceof ConfigurableListableBeanFactory &&
            AutoProxyUtils.shouldProxyTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName));
    
}

工厂默认实现 DefaultListableBeanFactory 类实现了 ConfigurableListableBeanFactory 接口。

跟踪 AutoProxyUtils 类的 shouldProxyTargetClass 方法。

public static boolean shouldProxyTargetClass(ConfigurableListableBeanFactory beanFactory, String beanName) {
    
    // 工厂中有对应 beanName 的 bean definition 则进入条件
    if (beanName != null && beanFactory.containsBeanDefinition(beanName)) {
        BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
        
        // bean definition 的 attributes 属性中是否有
        // org.springframework.aop.framework.autoproxy.AutoProxyUtils.preserveTargetClass
        // 为 key 的属性,且 value 为 ture
        return Boolean.TRUE.equals(bd.getAttribute(PRESERVE_TARGET_CLASS_ATTRIBUTE));
    }
    return false;
}

如果被代理 bean 对应的 bean definition 属性中,存在org.springframework.aop.framework.autoproxy.AutoProxyUtils.preserveTargetClass为 key,且 值为 true 的 attributes

那么设置 proxyTargetClass 为 ture

再看第二个方法

evaluateProxyInterfaces

该方法在类 ProxyProcessorSupport 中实现,ProxyProcessorSupport 是 AbstractAutoProxyCreator 的父类

/**
* Check the interfaces on the given bean class and apply them to the {@link ProxyFactory},
* if appropriate.
* <p>Calls {@link #isConfigurationCallbackInterface} and {@link #isInternalLanguageInterface}
* to filter for reasonable proxy interfaces, falling back to a target-class proxy otherwise.
* 
* 检查指定 bean class 上的接口,如果合适的话设置到 ProxyFactory 中。
* 调用 isConfigurationCallbackInterface 方法和 isInternalLanguageInterface 方法去过滤得到
* 合理的代理接口,否则回退到 target-class proxy
*/
protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
    
    // 此方法拿到类上及其父类上,所有的接口,不会递归获取接口上的接口
    Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
    boolean hasReasonableProxyInterface = false;
    
    // 遍历所有的接口,并进行过滤
    for (Class<?> ifc : targetInterfaces) {
        
        // 接口中不能有像 Aware、InitializingBean 等容器的回调接口
        // 接口的 ClassName 也不能是以 .cglib.proxy.Factory 结尾或者是 groovy.lang.GroovyObject
        // 这样的内部语言接口
        if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&
            ifc.getMethods().length > 0) {
            
            // 如果还有接口剩余,则存在合适的代理接口
            hasReasonableProxyInterface = true;
            break;
        }
    }
    if (hasReasonableProxyInterface) {
        
        // 将代理接口一个个添加到 proxyFactory 中
        for (Class<?> ifc : targetInterfaces) {
            proxyFactory.addInterface(ifc);
        }
    }
    else {
        
        // 否者 proxyTargetClass 属性设置为 true
        proxyFactory.setProxyTargetClass(true);
    }
}

总结一下两个方法

当 xml 中没有配置 proxyTargetClass 属性,默认为 false

如果被代理 bean 对应的 bean definition ,它的 attributes 属性中,存在org.springframework.aop.framework.autoproxy.AutoProxyUtils.preserveTargetClass为 key,值为 true 的键值对

那么设置 proxyTargetClass 为 ture

否则过滤所有接口,接口不能为 Aware、InitializingBean 等容器的回调接口,也不能是内部语言接口

如果没有合适的接口,proxyTargetClass 还是设置为 true 。

接下来看下代理工厂获取代理的流程。

getProxy

进入 ProxyFactory 类中,跟踪 getProxy 方法

/**
* Create a new proxy according to the settings in this factory.
* <p>Can be called repeatedly. Effect will vary if we've added
* or removed interfaces. Can add and remove interceptors.
* <p>Uses the given class loader (if necessary for proxy creation).
*
* 根据这个 factory 的设置创建一个新的代理。
* 可以被重复调用。如果我们添加或者移除了接口,会有影响。
* 可以添加和移除拦截器。
* 使用指定的类加载器(如果需要代理创建)
*/
public Object getProxy(@Nullable ClassLoader classLoader) {
    return createAopProxy().getProxy(classLoader);
}

先跟踪 createAopProxy 方法,此方法在 ProxyCreatorSupport 类中实现,ProxyFactory 是其子类。

/**
* Subclasses should call this to get a new AOP proxy. They should <b>not</b>
* create an AOP proxy with {@code this} as an argument.
*
* 子类应该调用这个方法去获得一个新的AOP代理。他们不应该用 this 作为参数创建一个AOP代理
*/
protected final synchronized AopProxy createAopProxy() {
    
    // 当AOP代理第一次被创建时,active会被设置为true
    if (!this.active) {
        
        // 设置 active 为 true,激活代理配置
        activate();
    }
    return getAopProxyFactory().createAopProxy(this);
}

getAopProxyFactory 方法拿到的是 DefaultAopProxyFactory 的实例,它的接口是 AopProxyFactory

ProxyFactory 类间接继承 AdvisedSupport ,AdvisedSupport 继承 ProxyConfig ,作为配置存在

ProxyFactory 类和 DefaultAopProxyFactory 并没有继承关系

以 ProxyFactory 类的实例为参数,调用 createAopProxy 方法,继续跟踪

createAopProxy

此方法在 DefaultAopProxyFactory 类中实现,采用 JDK proxy 代理还是使用 cglib 代理,在这个方法中决定

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: " +
                                         "Either an interface or a target is required for proxy creation.");
        }
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        return new JdkDynamicAopProxy(config);
    }
}

isOptimize 方法就是返回 ProxyFactory 的 optimize 属性,为布尔值

是否执行积极优化的含义。

优化通常意味着,在代理创建后,通知的变化不会带来影响,默认下为 false。

optimize 在此处也被作为了一个判断依据。

optimize 可以参考文章:https://blog.csdn.net/zh199609/article/details/79710846

isProxyTargetClass 方法拿的则是 ProxyFactory 的 proxyTargetClass 属性,前面已经跟踪过。

hasNoUserSuppliedProxyInterfaces 方法在代理接口不存在,或者只有一个且是 SpringProxy 接口的子接口情况下,才返回 true 。

当上述三个方法都返回 false 时,代理才走的 JDK proxy 代理,也就是接口代理。

当满足其中一个条件,进入方法后,还有一层筛选,要么 target Class 是一个接口,要么是 Proxy 类的子类,否则其余情况都使用 cglib 代理,也就是类代理。

最后调用代理的 getProxy 方法。不同代理的实现,其实就是spring对 JDK 的 Proxy,或者 cglib 的 Enhancer 的封装。最终完成AOP的实现。

JDK 和 CGLib

1、CGLib所创建的动态代理对象在实际运行时候的性能要比JDK动态代理高不少;

2、但是CGLib在创建对象的时候所花费的时间却比JDK动态代理要多很多;

3、因此,对于singleton的代理对象或者具有实例池的代理,因为无需频繁的创建代理对象,所以比较适合采用CGLib动态代理,反正,则比较适用JDK动态代理

参考:https://blog.csdn.net/xlgen157387/article/details/82497594

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349