Spring AOP實現原理簡介

AOP聯盟標準

AOP聯盟將AOP體系分爲三層,從三層結構可以看出,AOP實現方式有很多種,包括反射、元數據處理、程序處理、攔截器處理等,通過本節學習,你就會看到Spring AOP的實現使用的是Java語言本身的特性,即Java Proxy代理類、攔截器技術實現。

AOP簡介

概念

切面(Aspect) :官方的抽象定義爲“一個關注點的模塊化,這個關注點可能會橫切多個對象”。
連接點(Joinpoint) :程序執行過程中的某一行爲。
通知(Advice) :“切面”對於某個“連接點”所產生的動作。
切入點(Pointcut) :匹配連接點的斷言,在AOP中通知和一個切入點表達式關聯。
目標對象(Target Object) :被一個或者多個切面所通知的對象。
AOP代理(AOP Proxy) 在Spring AOP中有兩種代理方式,JDK動態代理和CGLIB代理。

通知(Advice)類型
前置通知(Before advice) :在某連接點(JoinPoint)之前執行的通知,但這個通知不能阻止連接點前的執行。ApplicationContext中在<aop:aspect>裏面使用<aop:before>元素進行聲明。
後通知(After advice) :當某連接點退出的時候執行的通知(不論是正常返回還是異常退出)。ApplicationContext中在<aop:aspect>裏面使用<aop:after>元素進行聲明。
返回後通知(After return advice) :在某連接點正常完成後執行的通知,不包括拋出異常的情況。ApplicationContext中在<aop:aspect>裏面使用<after-returning>元素進行聲明。
環繞通知(Around advice) :包圍一個連接點的通知,類似Web中Servlet規範中的Filter的doFilter方法。可以在方法的調用前後完成自定義的行爲,也可以選擇不執行。ApplicationContext中在<aop:aspect>裏面使用<aop:around>元素進行聲明。
拋出異常後通知(After throwing advice) : 在方法拋出異常退出時執行的通知。 ApplicationContext中在<aop:aspect>裏面使用<aop:after-throwing>元素進行聲明。

切入點表達式 :如execution(* com.spring.service.*.*(..))

特點

1、降低模塊之間的耦合度

2、使系統容易擴展

3、更好的代碼複用。

時序圖


流程說明

1)AOP標籤的定義解析劉徹骨肯定是從NamespaceHandlerSupport的實現類開始解析的,這個實現類就是AopNamespaceHandler。至於爲什麼會是從NamespaceHandlerSupport的實現類開始解析的,這個的話我想讀者可以去在回去看看Spring自定義標籤的解析流程,裏面說的比較詳細。

2)要啓用AOP,我們一般會在Spring裏面配置<aop:aspectj-autoproxy/>  ,所以在配置文件中在遇到aspectj-autoproxy標籤的時候我們會採用AspectJAutoProxyBeanDefinitionParser解析器

3)進入AspectJAutoProxyBeanDefinitionParser解析器後,調用AspectJAutoProxyBeanDefinitionParser已覆蓋BeanDefinitionParser的parser方法,然後parser方法把請求轉交給了AopNamespaceUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary去處理

4)進入AopNamespaceUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法後,先調用AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法,裏面在轉發調用給registerOrEscalateApcAsRequired,註冊或者升級AnnotationAwareAspectJAutoProxyCreator類。對於AOP的實現,基本是靠AnnotationAwareAspectJAutoProxyCreator去完成的,它可以根據@point註解定義的切點來代理相匹配的bean。

5)AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法處理完成之後,接下來會調用useClassProxyingIfNecessary() 處理proxy-target-class以及expose-proxy屬性。如果將proxy-target-class設置爲true的話,那麼會強制使用CGLIB代理,否則使用jdk動態代理,expose-proxy屬性是爲了解決有時候目標對象內部的自我調用無法實現切面增強。

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

創建AOP代理

上面說到AOP的核心邏輯是在AnnotationAwareAspectJAutoProxyCreator類裏面實現,那麼我們先來看看這個類的層次關係

這個類實現了BeanPostProcessor接口,那就意味着這個類在spring加載實例化前會調用postProcessAfterInitialization方法,對於AOP的邏輯也是由此開始的。

時序圖

流程說明

1)spring 容器啓動,每個bean的實例化之前都會先經過AbstractAutoProxyCreator類的postProcessAfterInitialization()這個方法,然後接下來是調用wrapIfNecessary方法。

/** 
 * Create a proxy with the configured interceptors if the bean is 
 * identified as one to proxy by the subclass. 
 * @see #getAdvicesAndAdvisorsForBean 
 */  
public Object postProcessAfterInitialization(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;  
} 

2)進入wrapIfNecessary方法後,我們直接看重點實現邏輯的方法getAdvicesAndAdvisorsForBean,這個方法會提取當前bean 的所有增強方法,然後獲取到適合的當前bean 的增強方法,然後對增強方法進行排序,最後返回

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

3)獲取到當前bean的增強方法後,便調用createProxy方法,創建代理。先創建代理工廠proxyFactory,然後獲取當前bean 的增強器advisors,把當前獲取到的增強器添加到代理工廠proxyFactory,然後設置當前的代理工的代理目標對象爲當前bean,最後根據配置創建JDK的動態代理工廠,或者CGLIB的動態代理工廠,然後返回proxyFactory

/** 
     * Create an AOP proxy for the given bean. 
     * @param beanClass the class of the bean 
     * @param beanName the name of the bean 
     * @param specificInterceptors the set of interceptors that is 
     * specific to this bean (may be empty, but not null) 
     * @param targetSource the TargetSource for the proxy, 
     * already pre-configured to access the bean 
     * @return the AOP proxy for the bean 
     * @see #buildAdvisors 
     */  
    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);  
    }  

AOP動態代理執行

關於AOP的動態代理執行,有兩種主要的方式JDK的動態代理和CGLIB的動態代理,接下來,我們先來看看AOP動態代理的實現選擇方式,先上核心實現代碼:

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

Spring JDK動態代理實現


在上面的第三步驟說道或根據用戶的配置(例如是否配置了proxyTargetClass屬性爲true),選擇創建的代理類型,這個的代理類型分兩種實現,都是比較高效的,下面根據JDK的動態代理來說明AOP的執行,也是先上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();  
           }  
   
           //獲取可以應用到此方法上的Interceptor列表  
           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)獲取攔截器
2)判斷攔截器鏈是否爲空,如果是空的話直接調用切點方法
3)如果攔截器不爲空的話那麼便創建ReflectiveMethodInvocation類,把攔截器方法都封裝在裏面,也就是執行getInterceptorsAndDynamicInterceptionAdvice方法

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {  
                   MethodCacheKeycacheKey = new MethodCacheKey(method);  
                   List<Object>cached = this.methodCache.get(cacheKey);  
                   if(cached == null) {  
                            cached= this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(  
                                               this,method, targetClass);  
                            this.methodCache.put(cacheKey,cached);  
                   }  
                   returncached;  
         }  

4)其實實際的獲取工作其實是由AdvisorChainFactory. getInterceptorsAndDynamicInterceptionAdvice()這個方法來完成的,獲取到的結果會被緩存,下面來分析下這個方法的實現:

/** 
    * 從提供的配置實例config中獲取advisor列表,遍歷處理這些advisor.如果是IntroductionAdvisor, 
    * 則判斷此Advisor能否應用到目標類targetClass上.如果是PointcutAdvisor,則判斷 
    * 此Advisor能否應用到目標方法method上.將滿足條件的Advisor通過AdvisorAdaptor轉化成Interceptor列表返回. 
    */  
    publicList getInterceptorsAndDynamicInterceptionAdvice(Advised config, Methodmethod, Class targetClass) {  
       // This is somewhat tricky... we have to process introductions first,  
       // but we need to preserve order in the ultimate list.  
       List interceptorList = new ArrayList(config.getAdvisors().length);  
   
       //查看是否包含IntroductionAdvisor  
       boolean hasIntroductions = hasMatchingIntroductions(config,targetClass);  
   
       //這裏實際上註冊一系列AdvisorAdapter,用於將Advisor轉化成MethodInterceptor  
       AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();  
   
       Advisor[] advisors = config.getAdvisors();  
        for (int i = 0; i <advisors.length; i++) {  
           Advisor advisor = advisors[i];  
           if (advisor instanceof PointcutAdvisor) {  
                // Add it conditionally.  
                PointcutAdvisor pointcutAdvisor= (PointcutAdvisor) advisor;  
                if(config.isPreFiltered() ||pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {  
                    //TODO: 這個地方這兩個方法的位置可以互換下  
                    //將Advisor轉化成Interceptor  
                    MethodInterceptor[]interceptors = registry.getInterceptors(advisor);  
   
                    //檢查當前advisor的pointcut是否可以匹配當前方法  
                    MethodMatcher mm =pointcutAdvisor.getPointcut().getMethodMatcher();  
   
                    if (MethodMatchers.matches(mm,method, targetClass, hasIntroductions)) {  
                        if(mm.isRuntime()) {  
                            // Creating a newobject instance in the getInterceptors() method  
                            // isn't a problemas we normally cache created chains.  
                            for (intj = 0; j < interceptors.length; j++) {  
                               interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptors[j],mm));  
                            }  
                        } else {  
                            interceptorList.addAll(Arrays.asList(interceptors));  
                        }  
                    }  
                }  
           } else if (advisor instanceof IntroductionAdvisor){  
                IntroductionAdvisor ia =(IntroductionAdvisor) advisor;  
                if(config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) {  
                    Interceptor[] interceptors= registry.getInterceptors(advisor);  
                    interceptorList.addAll(Arrays.asList(interceptors));  
                }  
           } else {  
                Interceptor[] interceptors =registry.getInterceptors(advisor);  
                interceptorList.addAll(Arrays.asList(interceptors));  
           }  
       }  
       return interceptorList;  
}  
5)這個方法執行完成後,Advised中配置能夠應用到連接點或者目標類的Advisor全部被轉化成了MethodInterceptor.

6)接下來貨到invoke方法中的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();  
       }  
   
       Object interceptorOrInterceptionAdvice =  
           this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);  
         
       //如果要動態匹配joinPoint  
       if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher){  
           // Evaluate dynamic method matcher here: static part will already have  
           // been evaluated and found to match.  
           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 {  
           // It's an interceptor, so we just invoke it: The pointcutwill have  
           // been evaluated statically before this object was constructed.  
           //執行當前Intercetpor  
           return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);  
       }  
}  
7)好了攔截器到這邊就可以執行了,複雜的代理終於可以起到他的作用了

Spring CGLIB動態代理實現

由於CGLIB的動態代理代碼量比較長,在這就不貼出來代碼了,其實這兩個代理的實現方式都差不多,都是創建方法調用鏈,不同的是jdk的動態代理創建的是
ReflectiveMethodInvocation調用鏈,而cglib創建的是CglibMethodInvocation

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