1. 程式人生 > >Spring AOP的實現:建立AopProxy代理物件

Spring AOP的實現:建立AopProxy代理物件

 

 

 

 

前面我們講述了AOP的基本知識以及在Spring AOP機制中的一些基本的資料結構及其功能。下面開始正式的講述Spring AOP的實現部分。

來看一下這個以ProxyFactory為中心的繼承關係圖

可以將ProxyConfig看做是一個數據基類,這個基類為ProxyFactoryBean這樣的子類提供了屬性的配置。而AdvisedSupport則是實現了對於通知器和通知的相關操作。

在分析Spring AOP的實現原理中。原書是以ProxyFactoryBean的實現作為例子的。通過這個工程Bean,生產出了我們需要的AopProxy代理物件。

那麼書上首先給了我們這樣的關於ProxyFactoryBean的配置方法。

我們可以看到,我們需要給我們的ProxyFactoryBean配置一個通知器,這個通知器是它的interceptorNames屬性。當然還需要配置proxyInterfaces,這個是目標介面,也就是被代理的介面。target ,目標物件。

值得注意一點,雖然這裡聲明瞭interceptorNames屬性,但是這個不是之後我會提到的攔截器。這個屬性宣告的是供AOP應用配置通知器的地方,需要為target目標物件生成Proxy代理物件,從而為AOP橫切面的編織做好準備工作。

在ProxyFactoryBean中,它的AOP實現需要依賴JDK或者CGLIB提供的Proxy特性(也就是我前面所說的代理模式)。從FactoryBean中獲取物件,是使用getObject()方法來完成的

@Override
	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();
		}
	}

首先要對通知器鏈進行初始化操作,通知器鏈封裝了一系列的攔截器,這些攔截器都要從配置中讀取,然後為代理物件的生成做好準備。Spring中有singleton和prototype型別這兩種不同的bean,所以這裡對代理物件的生成需要做一個區分。

現在來看一下initializeAdvisorChain();這個方法,它為Proxy代理物件配置Advistor鏈是在這個方法中完成的。從程式碼中我們可以看到,從ListableBeanFactory中取得相應的通知器並把這些通知器加入到通知器鏈中。

生成singleton代理物件是在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;
	}

首先需要設定代理物件的介面

setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));

之後我們會使用ProxyFactory來生成我們需要的Proxy。

this.singletonInstance = getProxy(createAopProxy());

 

protected Object getProxy(AopProxy aopProxy) {
		return aopProxy.getProxy(this.proxyClassLoader);
	}

 這裡使用的時候AopProxy的getProxy()方法生成代理物件。AopProxy的獲得方法是由

org.springframework.aop.framework.ProxyCreatorSupport.createAopProxy()

實現的

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

在DefaultAopProxyFactory中建立AopProxy

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

 接下里具體的代理物件的生成可以由兩種方式。AOP代理物件的生成,是根據我們的目標物件的型別。如果是介面類,那麼就使用JDK來生成代理物件,否則Spring使用CGLIB來生成目標物件的代理物件。當返回的是JDKDynamicAopProxy物件時。它的getProxy()方法如下所示

@Override
	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);
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}

在這個地方我們看到了

Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

這就是我之前的一篇部落格https://blog.csdn.net/qq1641530151/article/details/83036756

中提到的動態連結。這裡我們也可以看到,spring的底層實際上也呼叫了jdk的代理模式。

這個地方為我們返回了目標物件的代理物件。

關於CGLIB對於代理物件的生成方式,是類似的。書上也有相應的程式碼。

下次我將來講述關於Spring AOP的攔截器的呼叫。