天天看點

基于Spring源碼分析AOP的實作機制

Spring一個重要的特性就是提供了AOP,使得我們可以在原有的基礎上增加我們自己的系統業務邏輯。使得我們系統業務邏輯與應用業務邏輯相分離,耦合性降低,并且大大的提高了開發的效率。Spring的AOP利用的就是動态代理方式,在Spring的AOP中,有兩種實作方式。第一種,就是利用JDK的Proxy,另外一種就是采用CGLIB來實作的。

基本概念:

Advice:

   通知,制定在連接配接點做什麼,在Sping 中,他主要描述Spring 圍繞方法調用注入的額外的行為,具有增強的功能 ,隻能應用于所有方法,主要是由aopalliance.jar中包含aop定義中的接口,按這個接口實作aop标準。

PointCut

   切點,其決定一個 advice 應該應用于哪個連接配接點,也就是需要插入額外處理的地方的集合,例如,被某個advice 作為目标的一組方法。Spring pointcut 通常意味着标示方法,可以選擇一組方法調用作為pointcut。

Advisor:

   通知器,把Advice封閉起來,加入Pointcut(切入點),Spring就可以知道在什麼方法上攔截,以及攔截後所要做的具體行為了。Advisor有兩種實作NameMatchMethodPointcutAdvisor按方法名字比對。RegexpMethodPointcutAdvisor,按正則比對。

AOP建立:

   AOP的建立主要分為兩種一種是JDK的Proxy還有一種是CGLIB的,整個建立AOP的時序圖一樣,隻不過差異在于最終AOPProxy産生AOP的過程。

   首先AOP的具體建立的時序圖如下:

基于Spring源碼分析AOP的實作機制
   以該時序圖來分析我們AOP的建立過程。當我們使用AOP需要對某一個對象進行切面系統業務的時候,Spring會為該對象生成一個代理。具體是使用ProxyFactoryBean來配置我們的代理對象和方面行為。而具體的代理實作是通過JDK的Proxy或者CGLIB來完成的。ProxyFactoryBean是FactoryBean,調用該getObject方法:

public Object getObject() throws BeansException {
                //初始化通知器鍊,實際上就是注冊攔截器
    initializeAdvisorChain();
                if (isSingleton()) {
                    //傳回生成的一個單件Proxy
      return getSingletonInstance();
    }
    else {
                    ....
                  //傳回生成的Prototype的Proxy
    return newPrototypeInstance();
    }
}      

   整個方法包含了攔截器的初始化,以及擷取代理對象的代理的過程。

   第一行主要就是初始化通知器鍊,注冊被代理對象上的攔截器。

   當判斷是一個單例對象的時候,就會通過getSingletonInstance()來擷取單件

private synchronized Object getSingletonInstance()
{
      if (this.singletonInstance == null)
{
     this.targetSource = freshTargetSource();
      if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass())
          {
             //擷取要代理的類
            Class targetClass = getTargetClass();
            ...設定該類的接口類型
             setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
           }
          super.setFrozen(this.freezeProxy);
            //這裡才是真正的擷取Proxy,
             this.singletonInstance = getProxy(createAopProxy());
             }
    return this.singletonInstance;
}      

   在擷取單件的時候,首先要做的就是要擷取目标對象的接口,然後再次建立一個AopProxy來用于建立我們的AOP對象,這裡createAopProxy的調用就是調用具體父類ProxyCreatorSupport來完成建立一個DefaultAopProxyFactory。當我們new一個ProxyFactoryBean的時候,它會調用父類的無參構造器,這裡面就會預設的建立一個DefaultAopProxyFactory。這個就是我們預設的AOP代理工廠,最終是由它來決定我們到底使用JDK的Proxy還是CGLIB來建立代理的過程。在該類的成員屬性中cglibAvailable初始化的時候會監測

ClassUtils.isPresent("net.sf.cglib.proxy.Enhancer", DefaultAopProxyFactory.class.getClassLoader());是否目前路徑有cglib2

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException
{
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
    Class targetClass = config.getTargetClass();
                //代理類為空的時候
    if (targetClass == null) {
                ....
    }
               // 代理對象為接口的時候
    if (targetClass.isInterface()) {
         return new JdkDynamicAopProxy(config);
    }
    if (!cglibAvailable) {
                                                                                                                                                                                                                                  
    }
    eturn CglibProxyFactory.createCglibProxy(config);
    }
         else {
    return new JdkDynamicAopProxy(config);
 }      

   當我們的AopProxy産生後,接着就可以調用getProxy來傳回産生的代理對象,這裡以JdkDynamicAopProxy為例來分析其建立的過程。

public Object getProxy(ClassLoader classLoader) {
    if (logger.isDebugEnabled()) {
            ....}
    Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}      

   當我們的Spring建立了代理對象後,當調用目标對象上的方法時,将都會被代理到InvocationHandler類的invoke方法中執行。在這裡JdkDynamicAopProxy類實作了InvocationHandler接 口。

AOP攔截器

當使用JDK和CGLIB會生成不同的AopProxy代理對象,進而構造了不同的回調方法來啟動對攔截器鍊的調用,比如在JdkDynamicAopProxy中的invoke方法,以及Cglib2AopProxy中使用DynamicAdvisedInterceptor的intercept方法。它們都使用了不同的AopProxy代理對象,但最終對AOP攔截的處理都是基本一樣:它們對攔截器鍊的調用都是在ReflectiveMethodInvocation中通過proceed方法實作的。在這個proceed方法裡,會逐個運作攔截器的攔截方法。在運作攔截器的攔截方法之前,需要對代理方法完成一個比對判斷,通過這個比對判斷來決定攔截器是否滿足切面增強的要求。

   AOP攔截器的實作的時序圖如下:  

基于Spring源碼分析AOP的實作機制

   對目标的對象都會首先被代理至代理對象的invoke來調用,不管使用哪種建立代理對象的過程

下面是invoke的方法:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    MethodInvocation invocation;
    Object oldProxy = null;
    boolean setProxyContext = false;
    TargetSource targetSource = this.advised.targetSource;
    Class targetClass = null;
    Object target = null;
           try {
    if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
        return equals(args[0]);
    }
    if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
       return hashCode();
    }
    if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
    method.getDeclaringClass().isAssignableFrom(Advised.class)) {
    // 利用Proxy配置來調用服務,直接調用目标方法
    return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
    }
             Object retVal;
             if (this.advised.exposeProxy) {
             oldProxy = AopContext.setCurrentProxy(proxy);
             setProxyContext = true;
    }
                 //擷取所要代理的對象
    target = targetSource.getTarget();
    if (target != null) {
           targetClass = target.getClass();
    }
    // 獲得該方法上的攔截器鍊
    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
     //是否定義攔截器,否則直接調用目标對象的方法
    if (chain.isEmpty()) {
                 //直接調用目标對象的方法
                    retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
    }
    else {
          //如果不為空,則就建立一個ReflectiveMethodInvocation對象來先調用攔截器後調用目标方法
              invocation = new ReflectiveMethodInvocation
            (proxy, target, method, args, targetClass, chain);
    // 處理切入點上的攔截器的方法
    retVal = invocation.proceed();
    }
    if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) &&
    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
        retVal = proxy;
    }
           return retVal;
    }
    finally {
    if (target != null && !targetSource.isStatic()) {            
        targetSource.releaseTarget(target);
    }
    if (setProxyContext) {    
        AopContext.setCurrentProxy(oldProxy);
        }
    }      
public Object proceed() throws Throwable {
//直接調用目标方法,可能是攔截器調用結束或者無攔截器
//interceptorsAndDynamicMethodMatchers這個其實就是目标方法上的攔截器鍊的大小
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
}
//調用攔截器鍊上的對象,依次
Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher)
{
    // 這裡獲得相應的攔截器,如果攔截器可以比對的上的話,那就調用攔截器的invoke 方法     
    InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)     interceptorOrInterceptionAdvice;
     if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
        return dm.interceptor.invoke(this);
      }else {
           //調用攔截器鍊中的下一個攔截器
    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);
      }
}