1. 程式人生 > >Spring原始碼分析:AOP分析(一)

Spring原始碼分析:AOP分析(一)

前言

Spring 的兩大核心,一是IOC,我們之前已經學習過,而另一個則是大名鼎鼎的 AOP,AOP的具體概念我就不介紹了,我們今天重點是要從原始碼層面去看看 spring 的 AOP 是如何實現的。

在Spring AOP實現中,使用的核心技術是動態代理,生成代理類有兩種策略:jdk動態代理和cglib動態代理。

下面簡要的談一談這兩種代理

JDK動態代理

jdk 代理是基於介面實現的,最好的學習方式當然是看原始碼,因此這裡我們可以將生成的代理類匯出,再通過反編譯檢視程式碼,看看裡面是怎麼回事。

定義一個UserService介面:

public interface UserService {

    void add();

}

實現類UserServiceImpl

public class UserServiceImpl implements UserService {

    public void add() {
        System.out.println("--------------------add----------------------");
    }
}

編寫自己的InvocationHandler:

public class MyInvocationHandler implements InvocationHandler {

    private Object target;
    public MyInvocationHandler(Object target) {
        super();
        this.target = target;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("-----------------begin "+method.getName()+"-----------------");
        Object result = method.invoke(target, args);
        System.out.println("-----------------end "+method.getName()+"-----------------");
        return result;
    }
    public Object getProxy(){
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this);
    }

}

將代理類匯出:

public class JdkProxyTest {

    public static void main(String[] args) {

        //生成的代理類儲存到磁碟
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        UserService service = new UserServiceImpl();
        MyInvocationHandler handler = new MyInvocationHandler(service);
        UserService proxy = (UserService) handler.getProxy();
        proxy.add();
    }

}

現在JDK動態代理已經完成了,現在我們來看看生成的代理類反編譯結果:

public final class $Proxy0 extends Proxy implements UserService {
    //省略部分程式碼
    private static Method m3;
    public $Proxy0(InvocationHandler h) throws  {
        super(h);
    }
    //代理類的add 方法
    public final void add() throws  {
        try {
            //呼叫 InvocationHandler 的invoke方法
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
    
            m3 = Class.forName("com.study.spring.proxy.jdk.UserService").getMethod("add", new Class[0]);
            //省略部分程式碼
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

通過程式碼很容易就明白了,JDK動態代理是使用介面生成新的實現類,實現類裡面則委託給InvocationHandler,InvocationHandler裡面則呼叫被代理的類方法。

CGLIB 動態代理

同JDK代理一樣,通過程式碼來理解

編寫方法攔截器:

public class CglibProxy implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();
    public Object getProxy(Class clazz) {
        enhancer.setSuperclass(clazz);
        enhancer.setCallback( this);
        return enhancer.create();
    }

    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("-----------------begin "+method.getName()+"-----------------");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("-----------------end "+method.getName()+"-----------------");
        return result;
    }
}

匯出代理類:

public class CglibProxyTest {

    public static void main(String[] args){
        //生成代理類到本地
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "com/study/spring/proxy/cglib");
        UserServiceImpl service = new UserServiceImpl();
        CglibProxy cp = new CglibProxy();
        UserService proxy = (UserService) cp.getProxy(service.getClass());
        proxy.add();
    }
}

反編譯代理類,由於程式碼有點長,因此刪減了一部分:

public class UserServiceImpl$$EnhancerByCGLIB$$d166e24d extends UserServiceImpl implements Factory {
    private boolean CGLIB$BOUND;
    public static Object CGLIB$FACTORY_DATA;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static Object CGLIB$CALLBACK_FILTER;
    private static final Method CGLIB$add$0$Method;
    private static final MethodProxy CGLIB$add$0$Proxy;

    final void CGLIB$add$0() {
        super.add();
    }

    public final void add() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if(this.CGLIB$CALLBACK_0 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if(var10000 != null) {
            var10000.intercept(this, CGLIB$add$0$Method, CGLIB$emptyArgs, CGLIB$add$0$Proxy);
        } else {
            super.add();
        }
    }
    public UserServiceImpl$$EnhancerByCGLIB$$d166e24d() {
        CGLIB$BIND_CALLBACKS(this);
    }

    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
        CGLIB$THREAD_CALLBACKS.set(var0);
    }

    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
        CGLIB$STATIC_CALLBACKS = var0;
    }

    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        UserServiceImpl$$EnhancerByCGLIB$$d166e24d var1 = (UserServiceImpl$$EnhancerByCGLIB$$d166e24d)var0;
        if(!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if(var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if(CGLIB$STATIC_CALLBACKS == null) {
                    return;
                }
            }

            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }

    }

    public Object newInstance(Callback[] var1) {
        CGLIB$SET_THREAD_CALLBACKS(var1);
        UserServiceImpl$$EnhancerByCGLIB$$d166e24d var10000 = new UserServiceImpl$$EnhancerByCGLIB$$d166e24d();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Callback var1) {
        CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
        UserServiceImpl$$EnhancerByCGLIB$$d166e24d var10000 = new UserServiceImpl$$EnhancerByCGLIB$$d166e24d();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        UserServiceImpl$$EnhancerByCGLIB$$d166e24d var10000 = new UserServiceImpl$$EnhancerByCGLIB$$d166e24d;
        switch(var1.length) {
        case 0:
            var10000.<init>();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        default:
            throw new IllegalArgumentException("Constructor not found");
        }
    }

    public Callback getCallback(int var1) {
        CGLIB$BIND_CALLBACKS(this);
        MethodInterceptor var10000;
        switch(var1) {
        case 0:
            var10000 = this.CGLIB$CALLBACK_0;
            break;
        default:
            var10000 = null;
        }

        return var10000;
    }

    public void setCallback(int var1, Callback var2) {
        switch(var1) {
        case 0:
            this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
        default:
        }
    }

    public Callback[] getCallbacks() {
        CGLIB$BIND_CALLBACKS(this);
        return new Callback[]{this.CGLIB$CALLBACK_0};
    }

    public void setCallbacks(Callback[] var1) {
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
    }

    static {
        CGLIB$STATICHOOK1();
    }
}

通過程式碼我們知道,Cglib是通過直接繼承被代理類

從代理類裡面可知道對於原來的add函式,代理類裡面對應了兩個函式分別是add 和CGLIB$add$0
其中後者是在方法攔截器裡面呼叫的,前者則是我們使用代理類時候呼叫的函式。當我們程式碼呼叫add時候,會具體呼叫到方法攔截器的intercept方法。

整體上JDK代理和CGLIB代理思想上都是差不多的,jdk基於介面,cglib基於繼承(因此方法不能被final修飾)。

深入 AOP 原始碼實現

閱讀原始碼很好用的一個方法就是跑程式碼來除錯,因為自己一行一行地看的話,比較枯燥,而且難免會漏掉一些東西,為了更方便的除錯程式碼,這裡我們採用xml配置方式,簡要的實現aop功能。

同樣使用上面的 UserService 和UserServiceImpl類

建立一個Advice,這裡實現 MethodBeforeAdvice介面:

public class BeforeAdvice implements MethodBeforeAdvice {

    public void before(Method method, Object[] objects, @Nullable Object o) throws Throwable{
        System.out.println(o.getClass() + ":"+method.getName()+" 方法準備執行");
    }
}

xml:

<bean id="userService" class="com.study.spring.aop.UserServiceImpl"/>
	<!--advice-->
	<bean id="beforeAdvice" class="com.study.spring.aop.BeforeAdvice" />
	<bean id="userServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean" >
        <!--代理介面類-->
		<property name="proxyInterfaces" value="com.study.spring.aop.UserService"/>
		<!--代理實現類-->
		<property name="target"  ref="userService"/>
		
		<!--走CGLIB代理-->
		<!--<property name="proxyTargetClass"  value="true"/>-->
		
		<!--配置攔截器,這裡可以配置advice,advisor,interceptor-->
		<property name="interceptorNames">
			<!--引用我們beforeAdvice-->
			<list><value>beforeAdvice</value></list>
		</property>
</bean>

測試程式碼:

public void TestAOP(){

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

        ProxyFactoryBean abcProxy = (ProxyFactoryBean) context.getBean("&userServiceProxy");

        UserService userService= (UserService) abcProxy.getObject();

        userService.add();

        //實際獲取的是被FactoryBean 包裝後的bean
        userService = (UserService) context.getBean("userServiceProxy");

        userService.add();

}

執行結果這裡就不展示了,在呼叫add 方法前,都會先執行我們的BeforeAdvice,AOP生效。

上面的程式碼中又涉及到了FactoryBean,這個我們在前面講IOC的時候已經說過了,這裡當然也就不在說了,不知道的朋友,可以自行再去看看。

ProxyFactoryBean

程式碼很簡單,配置也很簡單,核心程式碼其實也就是ProxyFactoryBean,它是一個FactoryBean,那麼在getBean的時候,會呼叫該FactoryBean的getObject 方法,因此 ProxyFactoryBean 的 getObject 方法就是我們的入口了。

getObject

public Object getObject() throws BeansException {
	initializeAdvisorChain();
	if (isSingleton()) {
		return getSingletonInstance();
	}
	else {
		if (this.targetName == null) {
			logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
						"Enable prototype proxies by setting the 'targetName' property.");
		}
		return newPrototypeInstance();
	}
}

該方法很重要,首先初始化Advice鏈,然後獲取單例,這裡返回的就是我們最初看到的代理bean。這裡的初始化Advice鏈的重要作用就是將其連線起來,基本實現就是迴圈我們在配置檔案中(interceptorNames)配置的攔截器,按照連結串列的方式連線起來。

initializeAdvisorChain

/**
* Create the advisor (interceptor) chain. Advisors that are sourced
* from a BeanFactory will be refreshed each time a new prototype instance
* is added. Interceptors added programmatically through the factory API
* are unaffected by such changes.
*/
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
	if (this.advisorChainInitialized) {
		return;
	}
	if (!ObjectUtils.isEmpty(this.interceptorNames)) {
		if (this.beanFactory == null) {
			throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
						"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
		}

		// Globals can't be last unless we specified a targetSource using the property...
	if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
			this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
			throw new AopConfigException("Target required after globals");
		}
	for (String name : this.interceptorNames) {
		if (name.endsWith(GLOBAL_SUFFIX)) {
			if (!(this.beanFactory instanceof ListableBeanFactory)) {
				throw new AopConfigException(
								"Can only use global advisors or interceptors with a ListableBeanFactory");
			}
			addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
							name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
		}
		else {
			Object advice;
			if (this.singleton || this.beanFactory.isSingleton(name)) {
				//根據name 獲取bean
				advice = this.beanFactory.getBean(name);
			}
				else {
					advice = new PrototypePlaceholderAdvisor(name);
				}
				addAdvisorOnChainCreation(advice, name);
			}
		}
	}

	this.advisorChainInitialized = true;
}

程式碼比較簡單,核心思想就是初始化我們配置的攔截器,裡面會遞迴呼叫getBean 方法。

我們著重關注下面的方法 getSingletonInstance();

getSingletonInstance

private synchronized Object getSingletonInstance() {
	if (this.singletonInstance == null) {
		this.targetSource = freshTargetSource();
		if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
			// Rely on AOP infrastructure to tell us what interfaces to proxy.
			Class<?> targetClass = getTargetClass();
			if (targetClass == null) {
				throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
			}
			setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
		}
		// Initialize the shared singleton instance.
		super.setFrozen(this.freezeProxy);
		this.singletonInstance = getProxy(createAopProxy());
	}
	return this.singletonInstance;
}

該方法是同步方法,防止併發錯誤,因為有共享變數。首先返回一個包裝過的目標物件,重要的一行是 getProxy(createAopProxy()),先建立AOP,再獲取代理。我們先看 crateAopProxy。

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

該方法返回一個AopProxy 型別的例項,我們看看該介面:

20181031094421

這是該介面的繼承圖,分別是 JdkDynamicAopProxy 動態代理和 CglibAopProxy 代理。

我們繼續看 createAopProxy 方法,該方法主要邏輯是建立一個AOP 工廠,預設工廠是 DefaultAopProxyFactory

DefaultAopProxyFactory

public ProxyCreatorSupport() {
   this.aopProxyFactory = new DefaultAopProxyFactory();
}

該類的 createAopProxy 方法則根據 ProxyFactoryBean 的一些屬性來決定建立哪種代理:

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

到這裡,我們知道 createAopProxy 方法有可能返回 JdkDynamicAopProxy 例項,也有可能返回 ObjenesisCglibAopProxy 例項,這裡總結一下:

如果被代理的目標類實現了一個或多個自定義的介面,那麼就會使用 JDK 動態代理,如果沒有實現任何介面,會使用 CGLIB 實現代理,如果設定了 proxy-target-class=“true”,那麼通常都會使用 CGLIB。

JDK 動態代理基於介面,所以只有介面中的方法會被增強,而 CGLIB 基於類繼承,需要注意就是如果方法使用了 final 修飾,或者是 private 方法,是不能被增強的

我們分別來看下兩個 AopProxy 實現類的 getProxy(classLoader) 實現。

JdkDynamicAopProxy

getProxy
public Object getProxy(@Nullable ClassLoader classLoader) {
	Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
	findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
	return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

java.lang.reflect.Proxy.newProxyInstance(…) 方法需要三個引數,第一個是 ClassLoader,第二個引數代表需要實現哪些介面,第三個引數最重要,是 InvocationHandler 例項,我們看到這裡傳了 this,因為 JdkDynamicAopProxy 本身實現了 InvocationHandler 介面。

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
	...
}

InvocationHandler 只有一個方法,當生成的代理類對外提供服務的時候,都會回到這個方法中:

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;
	Object target = null;

	try {
		if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
			// The target does not implement the equals(Object) method itself.
			// 代理equals 方法
			return equals(args[0]);
		}
		else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
			// The target does not implement the hashCode() method itself.
			// 代理hashCode 方法
			return hashCode();
		}
		else if (method.getDeclaringClass() == DecoratingProxy.class) {
			// There is only getDecoratedClass() declared -> dispatch to proxy config.
			return AopProxyUtils.ultimateTargetClass(this.advised);
		}
		else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
			// Service invocations on ProxyConfig with the proxy config...
			return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
		}

		Object retVal;
        // 如果設定了 exposeProxy,那麼將 proxy 放到 ThreadLocal 中
		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);

		// 建立一個 chain,包含所有要執行的 advice
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

		
		if (chain.isEmpty()) {
			// chain 是空的,說明不需要被增強
			Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
			retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
		}
		else {
			// We need to create a method invocation...
			invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
			//執行增強,並呼叫方法
			retVal = invocation.proceed();
		}

		//返回值檢查
		Class<?> returnType = method.getReturnType();
		if (retVal != null && retVal == target &&
					returnType != Object.class && returnType.isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
			// Special case: it returned "this" and the return type of the method
			// is type-compatible. Note that we can't help if the target sets
			// a reference to itself in another returned object.
			retVal = proxy;
		}
		else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
			throw new AopInvocationException(
						"Null return value from advice does not match primitive return type for: " + method);
		}
		return retVal;
	}
	finally {
		if (target != null && !targetSource.isStatic()) {
			// Must have come from TargetSource.
			targetSource.releaseTarget(target);
		}
		if (setProxyContext) {
			// Restore old proxy.
			AopContext.setCurrentProxy(oldProxy);
		}
	}
}

核心邏輯不算複雜,重點分析建立advice chain,然後呼叫方法程式碼那裡(44行~57行),可以進行斷點除錯,觀察一下執行流程,這裡就不繼續追下去了,感興趣的讀者自己去深入探索下,不是很難。

說完了 JDK 動態代理 JdkDynamicAopProxy,我們再來看一下 CGLIB 的代理實現 ObjenesisCglibAopProxy。

ObjenesisCglibAopProxy 繼承了 CglibAopProxy,而 CglibAopProxy 繼承了 AopProxy。

CglibAopProxy

在前面我們知道得到AopProxy後,會呼叫getProxy 方法,因此這裡我們直接就來看看該方法。

getProxy
public Object getProxy(@Nullable ClassLoader classLoader) {

	try {
		Class<?> rootClass = this.advised.getTargetClass();

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

從上面程式碼中,可以看到對CGLIB的使用,比如對Enhancer物件的配置,以及通過Enhancer 物件生成代理物件的過程。在這個生成代理物件的過程中,需要注意的是對Enhancer物件callback回撥的設定,正是這些回撥封裝了Spring AOP的實現,就像前面介紹的JDK的Proxy物件的invoke回撥方法一樣。在Enhancer的callback回撥設定中,實際上是通過設定DynamicAdvisedInterceptor攔截器來完成AOP功能的。

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
	// Parameters used for optimization choices...
	boolean exposeProxy = this.advised.isExposeProxy();
	boolean isFrozen = this.advised.isFrozen();
	boolean isStatic = this.advised.getTargetSource().isStatic();

	// Choose an "aop" interceptor (used for AOP calls).
	Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
	...
}

DynamicAdvisedInterceptor 引數中的 this.advised 是一個AdvisedSupport例項,這個是在建立AOpProxy的時候傳入的。

現在切入點在 DynamicAdvisedInterceptor 類了

DynamicAdvisedInterceptor

核心方法便是intercept 方法了,類似invoke 方法。

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())) {
			//如果攔截器為空,則直接進行方法呼叫
			Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
			retVal = methodProxy.invoke(target, argsToUse);
		}
		else {
			//攔截器呼叫,方法呼叫
			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);
		}
	}
}

方法邏輯和JdkDynamicAopProxy 中的invoke 方法是差不多的,這裡就不多說了。

總結

以ProxyFactoryBean為例,通過簡單的配置,對Spring AOP的基本實現和工作流程進行了簡單的梳理,通過ProxyFactoryBean 得到AopProxy物件。

通過使用AopProxy物件封裝target目標物件之後,ProxyFactoryBean的getObject方法得到的物件就不是一個普通的Java物件了,而是一個AoppProxy代理物件。在ProxyFactoryBean中配置的target目標物件,這時已經不會讓應用直接呼叫其方法實現,而是作為AOP實現的一部分。對target目標物件的方法呼叫會首先被AopProxy代理物件攔截,對於不同的AopProxy代理物件生成方法,會使用不同的攔截回撥入口。例如,對於JDK的AopProxy代理物件,使用是InvocationHandler的invoke回撥入口;而對於CGLIB的AopProxy代理物件,使用的是設定好的callback回撥,在這些callback 回撥中,對於AOP實現,是通過DynamicAdvisedInterceptor 來完成的,而DynamicAdvisedInterceptor的回撥入口是intercept方法。

參考

Spring 技術內幕