Spring源碼-AOP(四)-ProxyFactory

Spring AOP 源碼解析系列,建議你們按順序閱讀,歡迎討論設計模式

  1. Spring源碼-AOP(一)-代理模式
  2. Spring源碼-AOP(二)-AOP概念
  3. Spring源碼-AOP(三)-Spring AOP的四種實現
  4. Spring源碼-AOP(四)-ProxyFactory
  5. Spring源碼-AOP(五)-ProxyFactoryBean
  6. Spring源碼-AOP(六)-自動代理與DefaultAdvisorAutoProxyCreator
  7. Spring源碼-AOP(七)-整合AspectJ

本章來解析最基礎的ProxyFactory的源碼。有人會說,如今都沒人用編碼的方式來寫AOP了,解析它有什麼用呢?我想從兩點強調下:緩存

  1. 不管是註解仍是XML配置,其底層的實現仍是經過編碼的方式來組建相互之間的關係。能夠說ProxyFactory的基本實現就是Spring AOP拋開一切配置後真正核心的東西。
  2. 我理解中優秀的框架都是不斷演進的,逐漸演化從而造成強大的功能。從理解簡單的實現逐步到了解複雜的功能結構,才能一步步把握框架設計的思路,而這也是咱們學習優秀框架的主要目的。

1.ProxyFactory類結構

在深刻源碼前,咱們應當對ProxyFactory的結構有一個概覽,就如同讀一本書,先瀏覽下目錄結構,會對接下來的閱讀大有裨益。架構

ProxyFactory類結構

  • ProxyConfig:代理相關的全局配置,常見的有proxyTargetClass,exposeProxy。
  • AdvisedSupport:在Spring AOP中,Advisor(切面)就是將Advice(加強)和Pointcut(切入點)鏈接起來的東西。此類主要支持切面相關的操做。
  • ProxyCreatorSupport:代理建立的輔助類,主要方法就是建立代理對象。

能夠看出整個層級架構中每一個類的職責很肯定,符合了職責單一原則,在Spring中好的設計理念存在於點點滴滴裏。app

2.ProxyFactory源碼解析

在上一篇AOP的四種實現裏列舉了ProxyFactory建立代理的Demo。框架

public class ProxyFactoryTest {

	public static void main(String[] args) {
		// 1.建立代理工廠
		ProxyFactory factory = new ProxyFactory();
		// 2.設置目標對象
		factory.setTarget(new ChromeBrowser());
		// 3.設置代理實現接口
		factory.setInterfaces(new Class[]{Browser.class});
		// 4.添加前置加強
		factory.addAdvice(new BrowserBeforeAdvice());
		// 5.添加後置加強
		factory.addAdvice(new BrowserAfterReturningAdvice());
		// 6.獲取代理對象
		Browser browser = (Browser) factory.getProxy();
		
		browser.visitInternet();
	}
}

咱們就以基於接口代理這個簡單的例子來分析ProxyFactory的實現。ide

ProxyFactory初始化

首先,基於接口的代理須要準備的元素:函數

  1. 被代理的對象
  2. 代理對象要實現的接口
  3. 要對被代理對象實施的加強(額外操做)

Demo中的前5步都是處理準備工做性能

  1. ProxyFactory的構造函數是空方法學習

  2. setTarget時,將target對象封裝成TargetSource對象,而調用的setTargetSource是AdvisedSupport的方法。ui

    public void setTarget(Object target) {
     	setTargetSource(new SingletonTargetSource(target));
     }
    
    
     public void setTargetSource(TargetSource targetSource) {
     	this.targetSource = (targetSource != null ? targetSource : EMPTY_TARGET_SOURCE);
     }
  3. setInterfaces,賦值的也是AdvisedSupport中的interfaces屬性,可是是先清空再賦值。

    /**
      * Set the interfaces to be proxied.
      */
     public void setInterfaces(Class<?>... interfaces) {
     	Assert.notNull(interfaces, "Interfaces must not be null");
     	this.interfaces.clear();
     	for (Class<?> ifc : interfaces) {
     		addInterface(ifc);
     	}
     }
    
     /**
      * Add a new proxied interface.
      * [@param](https://my.oschina.net/u/2303379) intf the additional interface to proxy
      */
     public void addInterface(Class<?> intf) {
     	Assert.notNull(intf, "Interface must not be null");
     	if (!intf.isInterface()) {
     		throw new IllegalArgumentException("[" + intf.getName() + "] is not an interface");
     	}
     	if (!this.interfaces.contains(intf)) {
     		this.interfaces.add(intf);
     		adviceChanged();
     	}
     }
  4. addAdvice方法則是直接調用AdvisedSupport,將Advice封裝成Advisor而後添加到advisors集合中。

    public void addAdvice(int pos, Advice advice) throws AopConfigException {
     	Assert.notNull(advice, "Advice must not be null");
     	// 引用加強單獨處理
     	if (advice instanceof IntroductionInfo) {
     		// We don't need an IntroductionAdvisor for this kind of introduction:
     		// It's fully self-describing.
     		addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice));
     	}
     	// DynamicIntroductionAdvice不能單獨添加,必須做爲IntroductionAdvisor的一部分
     	else if (advice instanceof DynamicIntroductionAdvice) {
     		// We need an IntroductionAdvisor for this kind of introduction.
     		throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");
     	}
     	else {
     		addAdvisor(pos, new DefaultPointcutAdvisor(advice));
     	}
     }
    
     public void addAdvisor(int pos, Advisor advisor) throws AopConfigException {
     	if (advisor instanceof IntroductionAdvisor) {
     		validateIntroductionAdvisor((IntroductionAdvisor) advisor);
     	}
     	addAdvisorInternal(pos, advisor);
     }
    
     private void addAdvisorInternal(int pos, Advisor advisor) throws AopConfigException {
     	Assert.notNull(advisor, "Advisor must not be null");
     	if (isFrozen()) {
     		throw new AopConfigException("Cannot add advisor: Configuration is frozen.");
     	}
     	if (pos > this.advisors.size()) {
     		throw new IllegalArgumentException(
     				"Illegal position " + pos + " in advisor list with size " + this.advisors.size());
     	}
     	// 添加到advisor集合
     	this.advisors.add(pos, advisor);
     	updateAdvisorArray();
     	adviceChanged();
     }

上述的Advice都被封裝成DefaultPointcutAdvisor,能夠看下其構造函數

public DefaultPointcutAdvisor(Advice advice) {
	this(Pointcut.TRUE, advice);
}

Pointcut.TRUE表示支持任何切入點。

建立代理

準備工做作完了,直接經過getProxy方法獲取代理對象。

public Object getProxy() {
	return createAopProxy().getProxy();
}

這裏的createAopProxy()返回的是AopProxy類型,方法是final,而且加了鎖操做。

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

而AopProxy又是經過一個Factory工廠來建立,由於不一樣的外部配置決定了返回的是JDK代理仍是CGLIB代理。這裏涉及到兩種設計模式,工廠模式和策略模式,來看一張類圖。

能夠清晰地看出,AopProxyFactory->AopProxy->Prxoy之間的結構。

先來看DefaultAopProxyFactory中建立AopProxy的方法

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	// optimize=true或proxyTargetClass=true或接口集合爲空
	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.");
		}
		// 目標對象Class爲接口,正常使用時不會出現
		if (targetClass.isInterface()) {
			return new JdkDynamicAopProxy(config);
		}
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}

基於外部的配置,好比設置optimize或proxyTargetClass爲true,或者目標對象沒有實現接口,則會返回CGLIB代理(內部有個判斷targetClass是否爲接口的操做,本人嘗試過多種方式,除了硬編碼,正常配置時都不會走),不然返回JDK代理。

對於不一樣的代理方式,getProxy調用的是各自內部的實現。

JdkDynamicAopProxy

JDK代理經過Proxy.newProxyInstance來實現,而且JdkDynamicAopProxy自身實現InvocationHandler代理回調接口。

[@Override](https://my.oschina.net/u/1162528)
public Object getProxy() {
	return getProxy(ClassUtils.getDefaultClassLoader());
}

[@Override](https://my.oschina.net/u/1162528)
public Object getProxy(ClassLoader classLoader) {
	if (logger.isDebugEnabled()) {
		logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
	}
	// 處理代理接口
	Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
	// 判斷接口定義是否有equals和hashCode方法
	findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
	// 調用JDK建立代理方法
	return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

方法調用時的回調方法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 {
		// equals方法特殊處理
		if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
			// The target does not implement the equals(Object) method itself.
			return equals(args[0]);
		}
		// hashCode方法特殊處理
		if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
			// The target does not implement the hashCode() method itself.
			return hashCode();
		}
		// 調用Advised接口中的方法,直接反射執行
		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設置爲true,設置當前Proxy,它是ThreadLocal級別的
		if (this.advised.exposeProxy) {
			// Make invocation available if necessary.
			oldProxy = AopContext.setCurrentProxy(proxy);
			setProxyContext = true;
		}

		// May be null. Get as late as possible to minimize the time we "own" the target,
		// in case it comes from a pool.
		target = targetSource.getTarget();
		if (target != null) {
			targetClass = target.getClass();
		}

		// Get the interception chain for this method.
		// 獲取攔截器鏈
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

		// Check whether we have any advice. If we don't, we can fallback on direct
		// reflective invocation of the target, and avoid creating a MethodInvocation.
		// 若是攔截器鏈爲空,則直接反射調用
		if (chain.isEmpty()) {
			// 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.
			retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
		}
		else {
			// We need to create a method invocation...
			// 生成MethodInvocation,進行鏈式調用
			invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
			// Proceed to the joinpoint through the interceptor chain.
			retVal = invocation.proceed();
		}

		// Massage return value if necessary.
		// 支持返回this的流式調用
		Class<?> returnType = method.getReturnType();
		if (retVal != null && retVal == target && 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 {
		// 釋放target資源,由TargetSource子類實現
		if (target != null && !targetSource.isStatic()) {
			// Must have come from TargetSource.
			targetSource.releaseTarget(target);
		}
		// 恢復currentProxy,防止被誤用
		if (setProxyContext) {
			// Restore old proxy.
			AopContext.setCurrentProxy(oldProxy);
		}
	}
}

在整個調用過程當中,須要關注的有幾點:

  1. 若是設置exposeProxy,則會設置ThreadLocal級別的currentProxy爲當前執行方法的代理對象。能夠在方法內使用AopContext.currentProxy()來獲取代理對象。方法執行結束後,會在finally中清除currentProxy防止被誤用

  2. 攔截器鏈的獲取是一個通用方法,都是調用AdvisedSupport類,並設置了緩存以重用。

    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
     	MethodCacheKey cacheKey = 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);
     	}
     	return cached;
     }

真正的調用在DefaultAdvisorChainFactory中,它實現了AdvisorChainFactory接口。經過遍歷全部的Advisor切面,若是是PointcutAdvisor,則提取出Pointcut,而後匹配當前類和方法是否適用。另外經過AdvisorAdapterRegistry切面註冊適配器將Advisor中的Advice都封裝成MethodInteceptor以方便造成攔截器鏈。

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
		Advised config, Method method, Class<?> targetClass) {

	// This is somewhat tricky... We have to process introductions first,
	// but we need to preserve order in the ultimate list.
	List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
	Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
	// 是否有引入加強
	boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
	// 切面適配註冊器,封裝Advice爲Advisor或MethodInterceptor
	AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

	for (Advisor advisor : config.getAdvisors()) {
		// 切入點切面
		if (advisor instanceof PointcutAdvisor) {
			// Add it conditionally.
			PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
			// Advisor是否匹配當前對象
			if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
				// 獲取advisor全部攔截器
				MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
				MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
				// 當前方法是否使用切入點配置
				if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
					if (mm.isRuntime()) {
						// Creating a new object instance in the getInterceptors() method
						// isn't a problem as we normally cache created chains.
						for (MethodInterceptor interceptor : interceptors) {
							// 添加動態攔截器
							interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
						}
					}
					else {
						// 添加普通攔截器
						interceptorList.addAll(Arrays.asList(interceptors));
					}
				}
			}
		}
		// 引入加強單獨校驗添加
		else if (advisor instanceof IntroductionAdvisor) {
			IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
			if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}
		// 其餘類型的Advisor直接添加
		else {
			Interceptor[] interceptors = registry.getInterceptors(advisor);
			interceptorList.addAll(Arrays.asList(interceptors));
		}
	}

	return interceptorList;
}

3.鏈式調用,將全部元素封裝成ReflectiveMethodInvocation,經過方法proceed進行鏈式調用

invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
	
	retVal = invocation.proceed();

4.Spring對於方法返回this的流式調用也作出了兼容,將返回的this替換爲代理對象。

Class<?> returnType = method.getReturnType();
	if (retVal != null && retVal == target && 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;
	}

CglibAopProxy

CGLIB代理經過CglibAopProxy來實現,在Spring4.0時,封裝了一個ObjenesisCglibAopProxy,它繼承了CglibAopProxy。Objenesis是一個輕量級框架,能夠不調用構造函數來建立對象。另外它以代理對象的className爲key作了一層cache,屢次生成代理時能夠提升性能。

CGLIB經過Enhancer類生成字節碼對象,而後建立代理對象。來看下getProxy方法

public Object getProxy(ClassLoader classLoader) {
	if (logger.isDebugEnabled()) {
		logger.debug("Creating CGLIB proxy: target source is " + 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 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 UndeclaredThrowableStrategy(UndeclaredThrowableException.class));

		// 返回全部回調類
		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.
		// 生成代理Class並建立代理實例
		return createProxyClassAndInstance(enhancer, callbacks);
	}
	catch (CodeGenerationException ex) {
		throw new AopConfigException("Could not generate CGLIB subclass of class [" +
				this.advised.getTargetClass() + "]: " +
				"Common causes of this problem include using a final class or a non-visible class",
				ex);
	}
	catch (IllegalArgumentException ex) {
		throw new AopConfigException("Could not generate CGLIB subclass of class [" +
				this.advised.getTargetClass() + "]: " +
				"Common causes of this problem include using a final class or a non-visible class",
				ex);
	}
	catch (Exception ex) {
		// TargetSource.getTarget() failed
		throw new AopConfigException("Unexpected AOP exception", ex);
	}
}

getProxy方法是調用自CglibAopProxy類的,所作的無非就是建立Enhancer類,並配置目標對象,接口,回調類等,最後經過父類ObjenesisCglibAopProxy的createProxyClassAndInstance來建立或者返回緩存中的代理對象。對於CGLIB的原理這裏就不細究了,畢竟本人也未深刻了解(^__^)。咱們重點關注下回調操做,經過getCallbacks方法返回的Callback集合,只用關注下DynamicAdvisedInterceptor,它便是代理實際操做的回調類,回調方法爲intercept。

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		Object oldProxy = null;
		boolean setProxyContext = false;
		Class<?> targetClass = null;
		Object target = null;
		try {
			if (this.advised.exposeProxy) {
				// Make invocation available if necessary.
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}
			// May be null. Get as late as possible to minimize the time we
			// "own" the target, in case it comes from a pool...
			target = getTarget();
			if (target != null) {
				targetClass = target.getClass();
			}
			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.
				retVal = methodProxy.invoke(target, args);
			}
			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) {
				releaseTarget(target);
			}
			if (setProxyContext) {
				// Restore old proxy.
				AopContext.setCurrentProxy(oldProxy);
			}
		}
	}

能夠發現DynamicAdvisedInterceptor的intercept方法同JdkDynamicAopProxy的invoke方法幾乎相同,最後執行鏈式調用的CglibMethodInvocation也是ReflectiveMethodInvocation的子類。只是對一些特殊狀況選擇用其餘的Callback來輔助實現。

3.總結

看到這裏你可能以爲源碼仍是很複雜啊,是的,任何強大的功能的底層實現離不開對各類狀況的考慮以及異常的處理等等。可是優秀的框架會把複雜的實現細節封裝起來,而經過簡單的架構設計向外部暴露便捷的API。所以在看源碼的過程當中,不只要關注一些實現細節,更多地要關注整個架構的設計。對於Spring AOP來講,其實就是AopProxyFactory-AopProxy-Proxy三層結構,把握住這個就把握住了骨架,剩下的就是依附於骨架的血肉。

相關文章
相關標籤/搜索