Spring的AOP實現

如果需要在Spring中使用AOP是非常簡單的,只需要在Bean上加上@AspectJ,在方法上加@PointCut、@Before等註解就可以實現你想要的邏輯,最後在XML配置文件中加入<aop:aspectj-autoproxy>即可。

那麼Spring是如何實現的呢?

動態AOP標籤

我們從AopNamespaceHandler中的init()方法開始分析:

1.配置文件中在遇到aspectj-autoproxy標籤的時候我們會採用AspectJAutoProxyBeanDefinitionParser解析器

2.進入AspectJAutoProxyBeanDefinitionParser的parse方法,它將請求給了AopNamespaceUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary去處理

3.registerAspectJAnnotationAutoProxyCreatorIfNecessary方法中,先調用AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法完成註冊或者升級AnnotationAwareAspectJAutoProxyCreator類。對於AOP的實現,基本是靠AnnotationAwareAspectJAutoProxyCreator去完成的,它可以根據@point註解定義的切點來代理相匹配的bean。

4.接下來會調用useClassProxyingIfNecessary() 處理proxy-target-class以及expose-proxy屬性

5.最後的調用registerComponentIfNecessary 方法,註冊組建並且通知便於監聽器做進一步處理。

2.創建AOP代理

AOP主要是依靠AnnotationAwareAspectJAutoProxyCreator的實現的。那麼AnnotationAwareAspectJAutoProxyCreator是如何完成的?

AnnotationAwareAspectJAutoProxyCreator的層次結構:

這裏寫圖片描述

AnnotationAwareAspectJAutoProxyCreator實現了BeanPostProcessor接口,那就意味着這個類在spring加載實例化前會調用postProcessAfterInitialization方法。

public Object <strong>postProcessAfterInitialization</strong>(Object bean, String beanName) throws BeansException {  
    if (bean != null) {  
        Object cacheKey = getCacheKey(bean.getClass(), beanName);  
        if (!this.earlyProxyReferences.containsKey(cacheKey)) {  
            return wrapIfNecessary(bean, beanName, cacheKey);  
        }  
    }  
    return bean;  
}  

邏輯:
1.根據bean的class和name生成一個key。
2.如果適合代理就執行wrapIfNecessary(bean, beanName, cacheKey)。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {  
        if (beanName != null && this.targetSourcedBeans.containsKey(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;  
        }  
        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;  
    }  

邏輯:
1.如果以及處理過直接返回bean
2.不需要advisor返回bean
3.如果是基類或者說不需要自動代理返回bean。
4.獲得此類的advisor
5.創建代理

2.1 getAdvicesAndAdvisorsForBean

getAdvicesAndAdvisorsForBean主要邏輯由findEligibleAdvisors實現

protected List<Advisor> findEligibleAdvisors(Class beanClass, String beanName) {
2     List<Advisor> candidateAdvisors = findCandidateAdvisors();
3     List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
4     extendAdvisors(eligibleAdvisors);
5     if (!eligibleAdvisors.isEmpty()) {
6         eligibleAdvisors = sortAdvisors(eligibleAdvisors);
7     }
8     return eligibleAdvisors;
9 }

findEligibleAdvisors實現邏輯:
1.findCandidateAdvisors找到所有的Advisors
2.findAdvisorsThatCanApply找到匹配當前bean的Advisors。

findCandidateAdvisors源碼邏輯:
1.獲得beanFactory中註冊所有的BeanName
2.遍歷所有BeanName,找出有@AspectJ的類
3.對有@AspectJ的類提取advisor
4.將提取出的結果放入緩存。

findAdvisorsThatCanApply源碼邏輯:
從findCandidateAdvisors獲得的advisor中尋找適合當前class的advisor。

2.2 createProxy

protected Object createProxy(  
            Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {  

        ProxyFactory proxyFactory = new ProxyFactory();  
        // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.  
        proxyFactory.copyFrom(this);  

        if (!shouldProxyTargetClass(beanClass, beanName)) {  
            // Must allow for introductions; can't just set interfaces to  
            // the target's interfaces only.  
            Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);  
            for (Class<?> targetInterface : targetInterfaces) {  
                proxyFactory.addInterface(targetInterface);  
            }  
        }  

        Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);  
        for (Advisor advisor : advisors) {  
            proxyFactory.addAdvisor(advisor);  
        }  

        proxyFactory.<strong>setTargetSource</strong>(targetSource);  
        customizeProxyFactory(proxyFactory);  

        proxyFactory.setFrozen(this.freezeProxy);  
        if (advisorsPreFiltered()) {  
            proxyFactory.setPreFiltered(true);  
        }  
          //實現核心方法
        return proxyFactory.getProxy(this.proxyClassLoader);  
    }  

通過上面的源碼我們可以知道,對於代理的創建,Springle交給了proxyFactory的getProxy方法去完成,而之前的所有主要是爲proxyFactory做了初始準備而已。

2.2.1 ProxyFactory.getProxy(classLoader)

public object getProxy(ClassLoader classLoader){
    return createAopProxy().getProxy(classLoader);
}

createAopProxy創建代理:

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

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()) {  
            return new JdkDynamicAopProxy(config);  
        }  
        return CglibProxyFactory.createCglibProxy(config);  
    }  
    else {  
        return new JdkDynamicAopProxy(config);  
    }  
}  

上述代碼中的if判斷主要是對代理的選擇,使用JDK或者CGLIB實現代理,選擇完以後就創建了代理。

  • **optimize:**CGLIB創建的代理是否使用激進策略。
  • proxyTargetClass:當XML配置文件設置了<aop:aspectj-autoproxy proxy-target-class="true"/>時爲true,表示使用CGLIB
  • hasNoUserSuppliedProxyInterfaces:是否存在代理接口。

獲得代理

我們以使用JDK獲得代理做一下分析:
使用JDK方式最關鍵兩個方法:invoke和getProxy。
getProxy:獲得代理對象。
invoke:執行被代理對象的方法。
我們看一下JdkDynamicAopProxy的核心代碼invoke方法:

public Object invoke(Object proxy, Method method, Object[] args) throwsThrowable {  
       MethodInvocation invocation = null;  
       Object oldProxy = null;  
       boolean setProxyContext = false;  

       TargetSource targetSource = this.advised.targetSource;  
       Class targetClass = null;  
       Object target = null;  

       try {  
           //eqauls()方法,具目標對象未實現此方法  
           if (!this.equalsDefined && AopUtils.isEqualsMethod(method)){  
                return (equals(args[0])? Boolean.TRUE : Boolean.FALSE);  
           }  

           //hashCode()方法,具目標對象未實現此方法  
           if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)){  
                return newInteger(hashCode());  
           }  

           //Advised接口或者其父接口中定義的方法,直接反射調用,不應用通知  
           if (!this.advised.opaque &&method.getDeclaringClass().isInterface()  
                    &&method.getDeclaringClass().isAssignableFrom(Advised.class)) {  
                // Service invocations onProxyConfig with the proxy config...  
                return AopUtils.invokeJoinpointUsingReflection(this.advised,method, args);  
           }  

           Object retVal = null;  

           if (this.advised.exposeProxy) {  
                // Make invocation available ifnecessary.  
                oldProxy = AopContext.setCurrentProxy(proxy);  
                setProxyContext = true;  
           }  

           //獲得目標對象的類  
           target = targetSource.getTarget();  
           if (target != null) {  
                targetClass = target.getClass();  
           }  

           //獲取當前方法的攔截鏈
           List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,targetClass);  

           //如果沒有可以應用到此方法的通知(Interceptor),此直接反射調用 method.invoke(target, args)  
           if (chain.isEmpty()) {  
                retVal = AopUtils.invokeJoinpointUsingReflection(target,method, args);  
           } else {  
                //創建MethodInvocation,封裝攔截器鏈  
                invocation = newReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);  
                retVal = invocation.proceed();  
           }  

           // Massage return value if necessary.  
           if (retVal != null && retVal == target &&method.getReturnType().isInstance(proxy)  
                    &&!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {  
                // Special case: it returned"this" and the return type of the method  
                // is type-compatible. Notethat we can't help if the target sets  
                // a reference to itself inanother returned object.  
                retVal = proxy;  
           }  
           return retVal;  
       } finally {  
           if (target != null && !targetSource.isStatic()) {  
                // Must have come fromTargetSource.  
               targetSource.releaseTarget(target);  
           }  
           if (setProxyContext) {  
                // Restore old proxy.  
                AopContext.setCurrentProxy(oldProxy);  
           }  
       }  
    }  

1)獲取攔截器:getInterceptorsAndDynamicInterceptionAdvice
2)判斷攔截器鏈是否爲空,如果是空的話直接調用切點方法
3)如果攔截器不爲空的話那麼便創建ReflectiveMethodInvocation類,把攔截器方法都封裝在裏面
4)對攔截器鏈中的攔截器逐一調用:invocation.proceed()

看一下proceed方法:

public Object proceed() throws Throwable {  
       //  We start with an index of -1and increment early.  
       if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size()- 1) {  
           //如果Interceptor執行完了,則執行joinPoint  
           return invokeJoinpoint();  
       }  
       //獲得下一個攔截器interceptor
       Object interceptorOrInterceptionAdvice =  
           this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);  

       //如果要動態匹配joinPoint  
       if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher){  

           InterceptorAndDynamicMethodMatcher dm =  
                (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;  
           //動態匹配:運行時參數是否滿足匹配條件  
           if (dm.methodMatcher.matches(this.method, this.targetClass,this.arguments)) {  
                //執行當前Intercetpor  
                returndm.interceptor.invoke(this);  
           }  
           else {  
                //動態匹配失敗時,略過當前Intercetpor,調用下一個Interceptor  
                return proceed();  
           }  
       }  
       else {  
           //對於普通攔截器
           //執行當前Intercetpor  
           return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);  
       }  
}  

ReflectiveMethodInvocation中維護了攔截器調用的計數器,用來記錄當前調用鏈接的位置,使得可以有序的對攔截器逐一調用。

實現Aop自動代理總結:

1.<aop:aspectj-autoproxy/>解析註冊AnnotationAwareAspectJAutoProxyCreator類
2.AnnotationAwareAspectJAutoProxyCreator完成動態代理

AnnotationAwareAspectJAutoProxyCreator完成動態代理實現邏輯:
2.1.執行postProcessAfterInitialization()
———–如果適合代理就執行wrapIfNecessary()方法。

2.1.1wrapIfNecessary()實現邏輯:
1.判斷是否需要生成代理
2.如果需要則調用getAdvicesAndAdvisorsForBean()方法獲得當前類的advisor
3調用createProxy()創建代理。

2.1.1.2getAdvicesAndAdvisorsForBean()邏輯:
主要交給findEligibleAdvisors,實現邏輯:
—-1.findCandidateAdvisors找到所有的Advisors
—-2.findAdvisorsThatCanApply找到匹配當前bean的Advisors。

findCandidateAdvisors源碼邏輯:
—-1.獲得beanFactory中註冊所有的BeanName
—-2.遍歷所有BeanName,找出有@AspectJ的類
—-3.對有@AspectJ的類提取advisor
—-4.將提取出的結果放入緩存。

findAdvisorsThatCanApply源碼邏輯:
—-從findCandidateAdvisors獲得的advisor中尋找適合當前class的advisor。

2.1.1.3.調用createProxy()創建代理實現邏輯:
—-1.對ProxyFactory進行初始化
—-2.調用ProxyFactory.getProxy()創建代理

2.1.1.3.2.ProxyFactory.getProxy()實現邏輯:
調用 createAopProxy.getProxy(classLoader),邏輯如下
—-1.創建AopProxy:
——-對實現代理方式進行選擇:JDK?CGLIB?
——-調用JdkDynamicAopProxy的構造方法獲得代理。

JdkDynamicAopProxy的invoke方法:
1)獲取攔截器:getInterceptorsAndDynamicInterceptionAdvice
2)判斷攔截器鏈是否爲空,如果是空的話直接調用切點方法
3)如果攔截器不爲空的話那麼便創建ReflectiveMethodInvocation類,把攔截器方法都封裝在裏面
4)對攔截器鏈中的攔截器逐一調用:invocation.proceed()

proceed()方法:ReflectiveMethodInvocation中維護了攔截器調用的計數器,用來記錄當前調用鏈接的位置,使得可以有序的對攔截器逐一調用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章