Spring AOP 機(jī)制解讀

Spring AOP 機(jī)制源碼解讀

導(dǎo)讀

  • AOP是Spring框架面向切面的編程思想,AOP采用一種稱為“橫切”的技術(shù)关摇,將涉及多業(yè)務(wù)流程的通用功能抽取并單獨(dú)封裝屑埋,形成獨(dú)立的切面,在合適的時(shí)機(jī)將這些切面橫向切入到業(yè)務(wù)流程指定的位置中惋嚎。
  • 本文不會(huì)講解Spring切面的使用方法以及Spring切面的定義杠氢,但會(huì)通過一個(gè)示例引入話題。
  • 本文設(shè)計(jì)內(nèi)容主要說明Spring內(nèi)部如何幫我們做切面處理另伍,Spring是如何實(shí)現(xiàn)切面的鼻百,雖然Spring切面的底層實(shí)現(xiàn)還是基于動(dòng)態(tài)代理,但是本文并不會(huì)講解動(dòng)態(tài)代理摆尝,如果讀者不太了解動(dòng)態(tài)代理温艇,還需先連接器原理后再進(jìn)行本文的解讀,本文解讀需要一定的基礎(chǔ):如Spring bean的加載機(jī)制堕汞,Spring注解功能勺爱,Spring后置處理器,Spring BeanFactory讯检。

一 示例引入

1.1 目標(biāo)方法

下面是測試所用的目標(biāo)方法琐鲁,使用如下一個(gè)打印方法進(jìn)行測試:
方法很簡單,參入兩個(gè)int類型的輸入?yún)?shù)人灼,打印入?yún)⑽Ф危祷貎蓚€(gè)參數(shù)的除;
我們的需求是:在目標(biāo)方法運(yùn)行的時(shí)候進(jìn)行日志輸出(方法運(yùn)行前投放,方法運(yùn)行結(jié)束奈泪,或者方法運(yùn)行出現(xiàn)異常的時(shí)候,...)

public class MainPrint {

    public int print(int i, int j) {
        System.out.println("i = " + i + ", j = " + j);
        return i / j;
    }
}

1.2 定義切換類

定義切面如下所示:

  • 通過注解@Aspect告知Spring 該類是一個(gè)切面類跪呈。
  • 定義前置增加(@Before):logStart:在目標(biāo)方法(div)運(yùn)行之前運(yùn)行
  • 定義后置通知(@After):logEnd:在目標(biāo)方法(div)運(yùn)行結(jié)束之后運(yùn)行(無論方法正常結(jié)束還是異常結(jié)束)
  • 返回通知(@AfterReturning):logReturn:在目標(biāo)方法(div)正常返回之后運(yùn)行
  • 異常通知(@AfterThrowing):logException:在目標(biāo)方法(div)出現(xiàn)異常以后運(yùn)行
  • 環(huán)繞通知(@Around):動(dòng)態(tài)代理段磨,手動(dòng)推進(jìn)目標(biāo)方法運(yùn)行(joinPoint.procced());
@Aspect
public class LogsAspects {

    /**
     * 定義切入點(diǎn)
     */
    @Pointcut("execution(public int org.mzw.spring.annotation.aop.MainPrint.*(..))")
    public void pointCut(){};


    @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("org.mzw.spring.annotation.aop.LogsAspects.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+"}");
    }

    @AfterThrowing(value="pointCut()",throwing="exception")
    public void logException(JoinPoint joinPoint,Exception exception){
        System.out.println(""+joinPoint.getSignature().getName()+"異常。狼速。琅锻。異常信息:{"+exception+"}");
    }
}

1.3 基于注解配置

  • @EnableAspectJAutoProxy 通過添加該注解告知Spring啟動(dòng)AspectJAutoProxy 開啟基于注解的aop模式
@EnableAspectJAutoProxy
@Configuration
public class ConfigOfAOP {

    //業(yè)務(wù)邏輯類加入容器中
    @Bean
    public MainPrint calculator(){
        return new MainPrint();
    }

    //切面類加入到容器中
    @Bean
    public LogsAspects logsAspects(){
        return new LogsAspects();
    }
}

1.4 Main 啟動(dòng)容器

private static void starterSpringOfAop(Class<?>... clazz) {
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(clazz);
    MainPrint bean = applicationContext.getBean(MainPrint.class);
    int print = bean.print(2, 4);
    System.out.println(print);
}

輸出結(jié)果:

print運(yùn)行。向胡。恼蓬。@Before:參數(shù)列表是:{[2, 4]}
i = 2, j = 4
print結(jié)束。僵芹。处硬。@After
print正常返回。拇派。荷辕。@AfterReturning:運(yùn)行結(jié)果:{0}
0

實(shí)例很簡單,接下類看看這簡單的背后Spring是如何處理的件豌。
在上面示例中疮方,@Aspect告知Spring這是一個(gè)切面邏輯,只有另一處代碼我們需要關(guān)注苟径,那就是@EnableAspectJAutoProxy 該注解告知Spring 開啟切面功能案站。
所以我們需要重點(diǎn)關(guān)注下@EnableAspectJAutoProxy到底做了哪些騷操作躬审。

二 AOP代理創(chuàng)建源碼解讀

開啟基于注解的aop模式棘街;@EnableAspectJAutoProxy
了解Spring IOC的可以知道,Spring在啟動(dòng)的時(shí)候會(huì)注冊一些Bean承边,不同的Bean在不同的時(shí)機(jī)做不同的事情遭殉,所以我們也效仿這個(gè)模板去分析下Spring的AOP原理(容器中注冊了什么組件,這個(gè)組件什么時(shí)候工作博助,這個(gè)組件的功能是什么险污?)

2.1 EnableAspectJAutoProxy

2.1.1 @EnableAspectJAutoProxy 是什么?

我們在Spring的配置類上添加了這一注解@EnableAspectJAutoProxy 富岳,所以我們先分析下這個(gè)注解到底是做什么的蛔糯?
下面是EnableAspectJAutoProxy的源碼:這個(gè)是一個(gè)注解組件,除了注解常用的幾個(gè)用于注解的注解之外我們會(huì)發(fā)現(xiàn)一個(gè)特殊的注解@Import(AspectJAutoProxyRegistrar.class)

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

    /**
     * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
     * to standard Java interface-based proxies. The default is {@code false}.
     */
    boolean proxyTargetClass() default false;

    /**
     * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
     * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
     * Off by default, i.e. no guarantees that {@code AopContext} access will work.
     * @since 4.3.1
     */
    boolean exposeProxy() default false;
}

@Import 該組件可以向容器中注冊Bean,

  • {@link Configuration},
  • {@link ImportSelector},
  • {@link ImportBeanDefinitionRegistrar} * or regular component classes to import.

我們看到AspectJAutoProxyRegistrar 應(yīng)該是一個(gè)BeanDefinitionRegistrar, 給容器中導(dǎo)入AspectJAutoProxyRegistrar

2.1.2 AspectJAutoProxyRegistrar.class

利用AspectJAutoProxyRegistrar自定義給容器中注冊bean窖式;BeanDefinetion
源碼如下:

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * Register, escalate, and configure the AspectJ auto proxy creator based on the value
     * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
     * {@code @Configuration} class.
     */
    @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);
            }
        }
    }

}

2.1.3 registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
查看方法最終是給容器中注冊一個(gè)AnnotationAwareAspectJAutoProxyCreator.class

@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
        BeanDefinitionRegistry registry, @Nullable Object source) {
    return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

2.1.4 @EnableAspectJAutoProxy 注解小結(jié)

  • @EnableAspectJAutoProxy :利用@Import 給容器中導(dǎo)入AspectJAutoProxyRegistrar;
  • 利用AspectJAutoProxyRegistrar自定義給容器中注冊bean蚁飒;AnnotationAwareAspectJAutoProxyCreator

所以@EnableAspectJAutoProxy 注解的功能最終就是給Spring Ioc容器中注冊了一個(gè)Bean:AnnotationAwareAspectJAutoProxyCreator

2.2 AnnotationAwareAspectJAutoProxyCreator

我們先分析下AnnotationAwareAspectJAutoProxyCreator 這是一個(gè)什么組件,看下該類的繼承關(guān)系:如下圖(簡化后的:排除一些無關(guān)此話題的依賴樹):

AnnotationAwareAspectJAutoProxyCreator 2.png

上圖中關(guān)注標(biāo)紅的組件:

  • implements SmartInstantiationAwareBeanPostProcessor 后置處理器
  • BeanFactoryAware 自動(dòng)裝配BeanFactory

知道了這個(gè)組件是一個(gè)什么東西后我們就可以分析它具體做什么事情萝喘?

  1. 關(guān)注后置處理器淮逻,在bean初始化完成前后做事情琼懊?
  2. 裝配BeanFactory

這里暫時(shí)不說SpringIOC是如何加載AnnotationAwareAspectJAutoProxyCreator的邏輯,這里暫時(shí)只分析AnnotationAwareAspectJAutoProxyCreator的作用爬早,后續(xù)有機(jī)會(huì)再針對(duì)Spring加載AnnotationAwareAspectJAutoProxyCreator進(jìn)行說明哼丈。

2.2.1 AbstractAutoProxyCreator

在該AnnotationAwareAspectJAutoProxyCreator組件的超類AbstractAutoProxyCreator 中顯示的裝配了BeanFactory

@Override
public void setBeanFactory(BeanFactory beanFactory) {
    this.beanFactory = beanFactory;
}

同時(shí)在該AbstractAutoProxyCreator組件中實(shí)現(xiàn)了后置處理器的邏輯
此處需要特殊說明下:

  • 一般我們實(shí)現(xiàn)BeanPostProcess 實(shí)現(xiàn)的方法是postProcessBeforeInitialization/postProcessAfterInitialization,該方法是Bean在調(diào)用初始化方法前后被調(diào)用,
  • 而此處我們實(shí)現(xiàn)InstantiationAwareBeanPostProcessor的方法是postProcessBeforeInstantiation/postProcessAfterInstantiation 該方法是在Bean實(shí)例化的前后進(jìn)行調(diào)用筛严;

補(bǔ)充說明:AbstractAutoProxyCreator實(shí)現(xiàn)了InstantiationAwareBeanPostProcessor 所以AnnotationAwareAspectJAutoProxyCreator組件的作用是在每個(gè)Bean創(chuàng)建之前調(diào)用postProcessBeforeInstantiation()

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    Object cacheKey = getCacheKey(beanClass, beanName);

    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }
    // Create proxy here if we have a custom TargetSource.
    // Suppresses unnecessary default instantiation of the target bean:
    // The TargetSource will handle target instances in a custom fashion.
    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;
}

/**
 * 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;
}   

2.2.2 方法 postProcessBeforeInstantiation

該方法一直跳過醉旦,所以此處不進(jìn)行分析

// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
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;
}

2.2.3 postProcessAfterInitialization

  • 嘗試從緩存中獲取bean名稱
  • 是否是早期代理引用
  • 如果不是則進(jìn)行增強(qiáng)嘗試
/**
 * 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;
}

關(guān)注該方法wrapIfNecessary 見名知意: 如果需要?jiǎng)t進(jìn)行增強(qiáng),

2.2.3 wrapIfNecessary

getAdvicesAndAdvisorsForBean.jpg
  • 判斷當(dāng)前bean是否在advisedBeans中(保存了所有需要增強(qiáng)bean)
  • 判斷當(dāng)前bean是否是基礎(chǔ)類型的Advice桨啃、Pointcut髓抑、Advisor、AopInfrastructureBean优幸, 或者是否是切面(@Aspect)
  • 是否需要跳過
    • 獲取候選的增強(qiáng)器(切面里面的通知方法)【List<Advisor> candidateAdvisors】每一個(gè)封裝的通知方法的增強(qiáng)器是 InstantiationModelAwarePointcutAdvisor吨拍;判斷每一個(gè)增強(qiáng)器是否是 AspectJPointcutAdvisor 類型的;返回true
    • 永遠(yuǎn)返回false
  • 創(chuàng)建代理對(duì)象
  • 放入緩存
  • 返回代理對(duì)象
/**
 * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
 * @param bean the raw bean instance
 * @param beanName the name of the bean
 * @param cacheKey the cache key for metadata access
 * @return a proxy wrapping the bean, or the raw bean instance as-is
 */
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;
    }

    // Create proxy if we have advice.
    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;
}
    

createProxy 創(chuàng)建代理對(duì)象

下面是createProxy 調(diào)用鏈

return proxyFactory.getProxy(getProxyClassLoader());
  • getProxy
public Object getProxy(@Nullable ClassLoader classLoader) {
    return createAopProxy().getProxy(classLoader);
}
  • createAopProxy
protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
        activate();
    }
    return getAopProxyFactory().createAopProxy(this);
}
  • getAopProxyFactory().createAopProxy
    DefaultAopProxyFactory#createAopProxy
    這里判斷使用哪種進(jìn)行代理
  • 如果目標(biāo)對(duì)象實(shí)現(xiàn)接口网杆,使用JDK動(dòng)態(tài)代理技術(shù) -> new JdkDynamicAopProxy(config);
  • 如果目標(biāo)對(duì)象沒有實(shí)現(xiàn)接口羹饰,則使用cglib動(dòng)態(tài)代理技術(shù) -> new ObjenesisCglibAopProxy(config);
@Override
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)用具體實(shí)現(xiàn)的代理工廠的getProxy 創(chuàng)建代理,
下面是CglibAopProxy的getProxy方法實(shí)現(xiàn):

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
    if (logger.isTraceEnabled()) {
        logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
    }

    try {
        Class<?> rootClass = this.advised.getTargetClass();
        Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

        Class<?> proxySuperClass = rootClass;
        if (ClassUtils.isCglibProxyClass(rootClass)) {
            proxySuperClass = rootClass.getSuperclass();
            Class<?>[] additionalInterfaces = rootClass.getInterfaces();
            for (Class<?> additionalInterface : additionalInterfaces) {
                this.advised.addInterface(additionalInterface);
            }
        }

        // Validate the class, writing log messages as necessary.
        validateClassIfNecessary(proxySuperClass, classLoader);

        // Configure CGLIB Enhancer...
        Enhancer enhancer = createEnhancer();
        if (classLoader != null) {
            enhancer.setClassLoader(classLoader);
            if (classLoader instanceof SmartClassLoader &&
                    ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                enhancer.setUseCache(false);
            }
        }
        enhancer.setSuperclass(proxySuperClass);
        enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
        enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
        enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

        Callback[] callbacks = getCallbacks(rootClass);
        Class<?>[] types = new Class<?>[callbacks.length];
        for (int x = 0; x < types.length; x++) {
            types[x] = callbacks[x].getClass();
        }
        // fixedInterceptorMap only populated at this point, after getCallbacks call above
        enhancer.setCallbackFilter(new ProxyCallbackFilter(
                this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
        enhancer.setCallbackTypes(types);

        // Generate the proxy class and create a proxy instance.
        return createProxyClassAndInstance(enhancer, callbacks);
    }
    catch (CodeGenerationException | IllegalArgumentException ex) {
        throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
                ": Common causes of this problem include using a final class or a non-visible class",
                ex);
    }
    catch (Throwable ex) {
        // TargetSource.getTarget() failed
        throw new AopConfigException("Unexpected AOP exception", ex);
    }
}

返回代理對(duì)象

createProxy.jpg

到此代理對(duì)象創(chuàng)建完畢碳却!

AOP 代理方法執(zhí)行邏輯源碼解析

代碼中我們獲取代理對(duì)象队秩,并執(zhí)行目標(biāo)方法
bean.print(2, 4);

private static void starterSpringOfAop(Class<?>... clazz) {
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(clazz);
    MainPrint bean = applicationContext.getBean(MainPrint.class);
    int print = bean.print(2, 4);
    System.out.println(print);
}

這里我們斷點(diǎn)打在bean.print(2, 4); 觀察下

intercept.jpg

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;
    Object target = null;
    TargetSource targetSource = this.advised.getTargetSource();
    try {
        if (this.advised.exposeProxy) {
            // Make invocation available if necessary.
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
        // Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        // Check whether we only have one InvokerInterceptor: that is,
        // no real advice, but just reflective invocation of the target.
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            // We can skip creating a MethodInvocation: just invoke the target directly.
            // Note that the final invoker must be an InvokerInterceptor, so we know
            // it does nothing but a reflective operation on the target, and no hot
            // swapping or fancy proxying.
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = methodProxy.invoke(target, argsToUse);
        }
        else {
            // We need to create a method invocation...
            retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
        }
        retVal = processReturnType(proxy, target, method, retVal);
        return retVal;
    }
    finally {
        if (target != null && !targetSource.isStatic()) {
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            // Restore old proxy.
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}   

2.3.1 核心代碼CglibMethodInvocation.proceed

// We need to create a method invocation... 
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
public CglibMethodInvocation(Object proxy, @Nullable Object target, Method method,
                Object[] arguments, @Nullable Class<?> targetClass,
                List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {

    super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);

    // Only use method proxy for public methods not derived from java.lang.Object
    this.methodProxy = (Modifier.isPublic(method.getModifiers()) &&
            method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) &&
            !AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ?
            methodProxy : null);
}

2.3.2 proceed

執(zhí)行步驟:

  1. 容器中保存了組件的代理對(duì)象(cglib增強(qiáng)后的對(duì)象)宪郊,這個(gè)對(duì)象里面保存了詳細(xì)信息(比如增強(qiáng)器泞边,目標(biāo)對(duì)象,xxx)燥翅;
  2. 根據(jù)ProxyFactory對(duì)象獲取將要執(zhí)行的目標(biāo)方法攔截器鏈关噪;
    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
  • List<Object> interceptorList保存所有攔截器 : 一個(gè)默認(rèn)的ExposeInvocationInterceptor 和 4個(gè)增強(qiáng)器鸟蟹;
  • 遍歷所有的增強(qiáng)器,將其轉(zhuǎn)為Interceptor使兔;registry.getInterceptors(advisor);
  • 將增強(qiáng)器轉(zhuǎn)為List<MethodInterceptor>建钥;如果是MethodInterceptor,直接加入到集合中,如果不是虐沥,使用AdvisorAdapter將增強(qiáng)器轉(zhuǎn)為MethodInterceptor熊经;轉(zhuǎn)換完成返回MethodInterceptor數(shù)組;
  1. 如果沒有攔截器鏈欲险,直接執(zhí)行目標(biāo)方法;攔截器鏈(每一個(gè)通知方法又被包裝為方法攔截器镐依,利用MethodInterceptor機(jī)制)
  2. 如果有攔截器鏈,把需要執(zhí)行的目標(biāo)對(duì)象槐壳,目標(biāo)方法,攔截器鏈等信息傳入創(chuàng)建一個(gè) CglibMethodInvocation 對(duì)象,并調(diào)用 Object retVal = mi.proceed();
  3. 攔截器鏈的觸發(fā)過程; 如果沒有攔截器執(zhí)行執(zhí)行目標(biāo)方法,或者攔截器的索引和攔截器數(shù)組-1大小一樣(指定到了最后一個(gè)攔截器)執(zhí)行目標(biāo)方法特幔;鏈?zhǔn)将@取每一個(gè)攔截器薄风,攔截器執(zhí)行invoke方法横辆,每一個(gè)攔截器等待下一個(gè)攔截器執(zhí)行完成返回以后再來執(zhí)行炫惩;攔截器鏈的機(jī)制芭毙,保證通知方法與目標(biāo)方法的執(zhí)行順序侈百;
public Object proceed() throws Throwable {
        //  We start with an index of -1 and increment early.
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }

        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            // Evaluate dynamic method matcher here: static part will already have
            // been evaluated and found to match.
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
            if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
                return dm.interceptor.invoke(this);
            }
            else {
                // Dynamic matching failed.
                // Skip this interceptor and invoke the next in the chain.
                return proceed();
            }
        }
        else {
            // It's an interceptor, so we just invoke it: The pointcut will have
            // been evaluated statically before this object was constructed.
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末胀葱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子朝群,更是在濱河造成了極大的恐慌姜胖,老刑警劉巖誉帅,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異右莱,居然都是意外死亡蚜锨,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門慢蜓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來亚再,“玉大人,你說我怎么就攤上這事晨抡》招” “怎么了?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵耘柱,是天一觀的道長如捅。 經(jīng)常有香客問我,道長调煎,這世上最難降的妖魔是什么镜遣? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮士袄,結(jié)果婚禮上悲关,老公的妹妹穿的比我還像新娘谎僻。我一直安慰自己,他們只是感情好寓辱,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布艘绍。 她就那樣靜靜地躺著,像睡著了一般讶舰。 火紅的嫁衣襯著肌膚如雪鞍盗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天跳昼,我揣著相機(jī)與錄音般甲,去河邊找鬼。 笑死鹅颊,一個(gè)胖子當(dāng)著我的面吹牛敷存,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播堪伍,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼锚烦,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了帝雇?” 一聲冷哼從身側(cè)響起涮俄,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎尸闸,沒想到半個(gè)月后彻亲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吮廉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年苞尝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宦芦。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡宙址,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出调卑,到底是詐尸還是另有隱情抡砂,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布令野,位于F島的核電站舀患,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏气破。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一餐抢、第九天 我趴在偏房一處隱蔽的房頂上張望现使。 院中可真熱鬧低匙,春花似錦、人聲如沸碳锈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽售碳。三九已至强重,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贸人,已是汗流浹背间景。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留艺智,地道東北人倘要。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像十拣,于是被迫代替她去往敵國和親封拧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容