1. 程式人生 > 程式設計 >SpringAop原始碼分析(基於註解)三:建立代理物件

SpringAop原始碼分析(基於註解)三:建立代理物件

在上篇文章SpringAop原始碼分析(基於註解)二:篩選通知器中,我們對AOP中通知的建立和篩選過程進行了分析,本章我們一起來看看,AOP是怎麼建立代理物件的。

我們先回到Bean初始化之後,呼叫BeanPostProcessor後置處理器的地方。

//AbstractAutoProxyCreator.java

//在Bean初始化之後回撥
@Override
public Object postProcessAfterInitialization(@Nullable Object bean,String beanName) throws BeansException {
	if (bean != null
) { Object cacheKey = getCacheKey(bean.getClass(),beanName); //判斷快取中是否有 if (!this.earlyProxyReferences.contains(cacheKey)) { // 沒有,為 bean 生成代理物件 return wrapIfNecessary(bean,beanName,cacheKey); } } return bean; } 複製程式碼

wrapIfNecessary程式碼:

//AbstractAutoProxyCreator.java

protected Object wrapIfNecessary
(Object bean,String beanName,Object cacheKey)
{ if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } /* * 如果是基礎設施類(Pointcut、Advice、Advisor 等介面的實現類),或是應該跳過的類, * 則不應該生成代理,此時直接返回 bean */
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(),beanName)) { this.advisedBeans.put(cacheKey,Boolean.FALSE); return bean; } // Create proxy if we have advice. <1> // 返回匹配當前 bean 的所有的通知器 advisor、advice、interceptor Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(),null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey,Boolean.TRUE); // 核心!建立代理物件 <2> Object proxy = createProxy( bean.getClass(),specificInterceptors,new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey,proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey,Boolean.FALSE); return bean; } 複製程式碼

上篇文章我們主要分析的是<1>處程式碼,現在有了合適的通知器,我們要為當前Bean建立代理物件,把通知器(Advisor)所持有的通知(Advice)織入到 bean 的某些方法前後。

看程式碼:

//AbstractAutoProxyCreator.java

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

	if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
		AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory,beanClass);
	}

	//建立代理工廠
	ProxyFactory proxyFactory = new ProxyFactory();
	proxyFactory.copyFrom(this);

	//proxyTargetClass是 @EnableAspectJAutoProxy 的屬性之一
	//true -> 強制使用CGLIB代理
	if (!proxyFactory.isProxyTargetClass()) {
		//false
		if (shouldProxyTargetClass(beanClass,beanName)) {
			proxyFactory.setProxyTargetClass(true);
		}
		else {
			//檢測 beanClass 是否實現了介面,若未實現,則將
			//proxyFactory 的成員變數 proxyTargetClass 設為 true
			evaluateProxyInterfaces(beanClass,proxyFactory);
		}
	}
    
        //封裝proxyFactory
	Advisor[] advisors = buildAdvisors(beanName,specificInterceptors);
	proxyFactory.addAdvisors(advisors);
	proxyFactory.setTargetSource(targetSource);
	customizeProxyFactory(proxyFactory);

	proxyFactory.setFrozen(this.freezeProxy);
	if (advisorsPreFiltered()) {
		proxyFactory.setPreFiltered(true);
	}

	// 建立並獲取代理物件
	return proxyFactory.getProxy(getProxyClassLoader());
	}
複製程式碼

這裡我們主要看下核心邏輯:

  • 建立代理工廠 ProxyFactory
  • 判斷使用JDK還是CGLIB
  • 封裝ProxyFactory
  • 建立並獲取代理物件

這裡的 isProxyTargetClass() 其實就是我們前面用的註解@EnableAspectJAutoProxy的屬性之一,當其為true時,強制使用CGLIB代理。

下面我們接著看建立代理的程式碼:

//ProxyFactory.java

public Object getProxy(@Nullable ClassLoader classLoader) {
	return createAopProxy().getProxy(classLoader);
}
複製程式碼

這段方法有兩個方法呼叫:

  • createAopProxy()
    建立 AopProxy 實現類物件
  • getProxy(classLoader)
    建立代理物件

我們先來看下createAopProxy():

//DefaultAopProxyFactory.java

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	//if中的3個條件
	//1、 config.isOptimize() - 是否需要優化
	//2、 config.isProxyTargetClass() - 檢測 proxyTargetClass 的值
	//3、 hasNoUserSuppliedProxyInterfaces(config) - 目標 bean 是否實現了介面
	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)) {
			//建立JdkDynamicAopProxy
			return new JdkDynamicAopProxy(config);
		}
		//建立CglibAopProxy
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		//建立JdkDynamicAopProxy
		return new JdkDynamicAopProxy(config);
	}
	}
複製程式碼

最終呼叫的是DefaultAopProxyFactory#createAopProxy(...)方法,通過這個方法建立AopProxy 的實現類,如: JdkDynamicAopProxy,然後根據這個實現類再建立代理物件。

我們以JdkDynamicAopProxy為例,看下getProxy(classLoader):

//JdkDynamicAopProxy.java

public Object getProxy() {
    return getProxy(ClassUtils.getDefaultClassLoader());
}

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,true);
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    
    // 呼叫 newProxyInstance 建立代理物件
    return Proxy.newProxyInstance(classLoader,proxiedInterfaces,this);
}
複製程式碼

直接看程式碼最後一行,最終呼叫 Proxy.newProxyInstance 方法建立代理物件。

參考:
www.tianxiaobo.com/2018/06/20/…