Spring AOP源碼淺析

1. Spring AOP示例代碼


示例代碼結(jié)構(gòu)如下圖所示:

其中切面類AspectObject的代碼:

@Aspect
@Component
public class AspectObject {

    //抽取公共的切入點(diǎn)表達(dá)式
    //1、本類引用
    //2、其他的切面引用
    @Pointcut("execution(public * io.zgc.spring.features.aop.annotation.TargetObject.*(..))")
    public void pointCut(){};

    //@Before在目標(biāo)方法之前切入;切入點(diǎn)表達(dá)式(指定在哪個(gè)方法切入)
    @Before("pointCut()")
    public void logStart(JoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        System.out.println(""+joinPoint.getSignature().getName()+"運(yùn)行。。。@Before:參數(shù)列表是:{"+ Arrays.asList(args)+"}");
    }

    @After("io.zgc.spring.features.aop.annotation.AspectObject.pointCut()")
    public void logEnd(JoinPoint joinPoint){
        System.out.println(""+joinPoint.getSignature().getName()+"結(jié)束。。。@After");
    }

    //JoinPoint一定要出現(xiàn)在參數(shù)表的第一位
    @AfterReturning(value="pointCut()",returning="result")
    public void logReturn(JoinPoint joinPoint,Object result){
        System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:運(yùn)行結(jié)果:{"+result+"}");
    }
}

被代理類TargetObject的代碼:

@Component
public class TargetObject implements TargetInterface{

    public String sayHello(String name) {
        System.out.println("hello,"+name);
        return "hello---"+name;
    }

}

測試客戶端Client的代碼:

package io.zgc.spring.features.aop.annotation;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Client {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopConfig.class);

        TargetInterface bean = applicationContext.getBean(TargetInterface.class);
        bean.sayHello("zgc");
        System.out.println(bean.getClass().getName());
    }
}

運(yùn)行測試代碼,輸入如下結(jié)果

sayHello運(yùn)行。。。@Before:參數(shù)列表是:{[zgc]}
hello,zgc
sayHello結(jié)束。。。@After
sayHello正常返回。。。@AfterReturning:運(yùn)行結(jié)果:{hello---zgc}
com.sun.proxy.$Proxy21

從輸出結(jié)果,可以看出TargetObject類,已經(jīng)被Spring修改成了代理類com.sun.proxy.$Proxy21并在sayHello方法執(zhí)行的織入了代理邏輯。接下來,我們就來分析下Spring是在什么地方以及通過什么方式將TargetObject替換成代理對象。

2. Debug調(diào)試


我們使用倒推的方式進(jìn)行debug,重點(diǎn)關(guān)注我們需要關(guān)注的代碼。

2.1. getBean調(diào)試

我們先假設(shè)代理對象實(shí)在獲取bean的時(shí)候發(fā)生的。

TargetInterface bean = applicationContext.getBean(TargetInterface.class);

Debug跟進(jìn)去發(fā)現(xiàn),它最終是在singletonObjects中將代理對象獲取出來的,而singletonObjects是個(gè)Map結(jié)構(gòu),它里面存放的是單例bean,可以簡單將其理解為bean工廠(tips:這種理解并不準(zhǔn)確)。

這里我們可以得出結(jié)論:代理對象的創(chuàng)建一定是包含在ApplicationContext對象創(chuàng)建的過程中。

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopConfig.class);

那我們就在singletonObjects放置值的地方加上斷點(diǎn),再通過程序的調(diào)用棧嘗試查看代理對象在什么地方生成。

為了減低干擾,斷點(diǎn)需要加上條件beanName.equals("targetObject");

2.2. ApplicationContext創(chuàng)建debug

上面斷點(diǎn)設(shè)置后,我們重新運(yùn)行程序,可以看到以下程序調(diào)用棧

我們向上追溯一下調(diào)用棧上的代碼,調(diào)用addSingleton()方法時(shí)已經(jīng)將代理對象通過入?yún)鬟f進(jìn)來。而DefaultSingletonBeanRegistry#getSingleton()的偽代碼如下:

  public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        synchronized (this.singletonObjects) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                ... ...
                try {
                    // 這里獲取targetObject的代理對象,實(shí)際會調(diào)用createBean方法
                    singletonObject = singletonFactory.getObject();
                }
                ... ...
                addSingleton(beanName, singletonObject);
            }
            return singletonObject;
        }
    }

繼續(xù)向上追溯, AbstractBeanFactory#doGetBean, 其偽代碼如下:

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
                          @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    // Create bean instance.
    if (mbd.isSingleton()) {
        sharedInstance = getSingleton(beanName, () -> {
            try {
                return createBean(beanName, mbd, args);
            }
            catch (BeansException ex) {
                ... ...
            }
        });
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }
    return (T) bean;
}

結(jié)合getSingletondoGetBean方法可知,當(dāng)調(diào)用ObjectFactorygetObject方法時(shí),會觸發(fā)ObjectFactory類的createBean方法執(zhí)行。

至此,我們知道了代理對象的創(chuàng)建是發(fā)生在createBean方法中,因此我們在此處增加條件斷點(diǎn),看看springcreateBean方法中做了哪些操作。

2.3. createBean調(diào)試

設(shè)置好斷點(diǎn)之后,我們重新執(zhí)行程序,一路step into。

圖中最下面的lambda$doGetBean就是我們給createBean設(shè)置斷點(diǎn)的地方。最終程序執(zhí)行到了AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization。其代碼如下:

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

        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessAfterInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }

可以看到這里是遍歷所有的BeanPostProcessor,然后依次執(zhí)行其postProcessAfterInitialization方法。此時(shí)Spring運(yùn)行的相關(guān)變量如下

這里注意一下,程序運(yùn)行到這里,TargetObject對應(yīng)的是原始對象,還沒有被代理。

另外當(dāng)前Spring上下文中包含的BeanPostProcessor中,有一個(gè)AnnotationAwareAspectJAutoProxyCreator。這個(gè)類是個(gè)后置處理器,它和代理對象的創(chuàng)建密不可分。

2.4. AnnotationAwareAspectJAutoProxyCreator調(diào)試

我們先來看看AnnotationAwareAspectJAutoProxyCreator類的繼承結(jié)構(gòu)

可以看到AnnotationAwareAspectJAutoProxyCreator類繼承了BeanPostProcessorBeanFactoryAware。而BeanFactoryAware接口的postProcessAfterInitialization方法是在父類AbstractAutoProxyCreator中實(shí)現(xiàn)。

下面接著上面的applyBeanPostProcessors方法繼續(xù)調(diào)試。

最終請求鏈路進(jìn)入到ProxyCreatorSupport#createAopProxy方法(接下來的代碼都是創(chuàng)建aop代理對象的核心邏輯),其源碼如下:

    protected final synchronized AopProxy createAopProxy() {
        if (!this.active) {
            activate();
        }
        return getAopProxyFactory().createAopProxy(this);
    }

DefaultAopProxyFactory#createAopProxy

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

最終調(diào)用JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)方法,其內(nèi)部同步JDK動態(tài)代理,創(chuàng)建代理對象。

Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

至此,我們已經(jīng)清楚的知道Spring是如何創(chuàng)建AOP代理對象。

2.5. 小結(jié)

Spring在創(chuàng)建IOC容器時(shí),通過Spring提供的后置處理器擴(kuò)展點(diǎn),先向容器注冊一個(gè)AnnotationAwareAspectJAutoProxyCreator后置處理器。再通過該后置處理器(其他后置處理器也如此)可以介入bean創(chuàng)建的生命周期,將原生bean通過JDK動態(tài)代理和cglib的方式替換成AOP代理類。

3. @EnableAspectJAutoProxy


上面還有一個(gè)疑問,AnnotationAwareAspectJAutoProxyCreator是怎么注冊到IOC容器中的?答案就是@EnableAspectJAutoProxy。

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

    boolean proxyTargetClass() default false;

    boolean exposeProxy() default false;

}

可以看到在@EnableAspectJAutoProxy注解中,為引入了(向容器注冊)AspectJAutoProxyRegistrar類。

@Import(AspectJAutoProxyRegistrar.class)

AspectJAutoProxyRegistrar類最終會引入AnnotationAwareAspectJAutoProxyCreator后置處理器,相關(guān)代碼如下:

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(
            AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

        AnnotationAttributes enableAspectJAutoProxy =
                AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        if (enableAspectJAutoProxy != null) {
            if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }

}

AopConfigUtils
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
            BeanDefinitionRegistry registry, @Nullable Object source) {

        return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
    }

注冊AnnotationAwareAspectJAutoProxyCreator的代碼最終是需要創(chuàng)建IOC容器時(shí)來觸發(fā),調(diào)用鏈路圖如下:

3.1. 創(chuàng)建和注冊AnnotationAwareAspectJAutoProxyCreator流程

流程:
1)、傳入配置類(或者配置文件),創(chuàng)建ioc容器
2)、注冊配置類,調(diào)用refresh()刷新容器;
3)、registerBeanPostProcessors(beanFactory);注冊bean的后置處理器來方便攔截bean的創(chuàng)建;


AnnotationAwareAspectJAutoProxyCreator創(chuàng)建時(shí)序圖

1、先獲取ioc容器已經(jīng)定義了的需要創(chuàng)建對象的所有BeanPostProcessor
2、給容器中加別的BeanPostProcessor
3、優(yōu)先注冊實(shí)現(xiàn)了PriorityOrdered接口的BeanPostProcessor;
4、再給容器中注冊實(shí)現(xiàn)了Ordered接口的BeanPostProcessor;
5、注冊沒實(shí)現(xiàn)優(yōu)先級接口的BeanPostProcessor;
6、注冊BeanPostProcessor,實(shí)際上就是創(chuàng)建BeanPostProcessor對象,保存在容器中;創(chuàng)建internalAutoProxyCreator BeanPostProcessor 【 AnnotationAwareAspectJAutoProxyCreator 】

  • 6.1. 創(chuàng)建Bean的實(shí)例
  • 6.2. populateBean;給bean的各種屬性賦值
  • 6.3. initializeBean:初始化bean;
    • 6.3.1. invokeAwareMethods():處理Aware接口的方法回調(diào)
    • 6.3.2. applyBeanPostProcessorsBeforeInitialization():應(yīng)用后置處理器的postProcessBeforeInitialization()
    • 6.3.3. invokeInitMethods();執(zhí)行自定義的初始化方法
    • 6.3.4. applyBeanPostProcessorsAfterInitialization();執(zhí)行后置處理器的postProcessAfterInitialization();
  • 6.4. BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)創(chuàng)建成功;--》aspectJAdvisorsBuilder
    1. 把BeanPostProcessor注冊到BeanFactory中;
beanFactory.addBeanPostProcessor(postProcessor);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容