Spring源碼-AOP(五)-ProxyFactoryBean

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

  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,它是Spring AOP核心的底層實現。然而硬編碼的方式仍是過於繁瑣且不易使用,本章咱們將討論ProxyFactoryBean,它結合了ProxyFactory和Ioc中的FactoryBean擴展,使得能夠經過XML配置的方式來實現Spring AOP。關於Spring AOP建立代理的具體實現本章將不會再贅述,而是主要討論FactoryBean擴展結合Spring AOP的使用。chrome

1.FactoryBean簡介

我在IOC容器(四)-FactoryBean一篇中已詳細地介紹了FactoryBean在Spring IOC中的實現原理,這裏仍是簡單介紹一下。緩存

FactoryBean顧名思義,工廠Bean,便可以動態建立Bean的Bean。對於一些只有在運行時才能明確的對象來講,直接在XML中定義已不能知足,而是經過定義一個工廠類,在運行時根據不一樣配置來生成最終的對象。框架

FactoryBean是Spring IOC的兩大擴展之一(另外一個是BeanPostProcessor),由此與Spring集成的功能衆多,包括但不限於AOP,ORM,事務管理,Remoting。ide

簡單看下AbstractBeanFactory中對FactoryBean處理的代碼this

// 單例
if (mbd.isSingleton()) {
	// 獲取單例的bean對象
	sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
		[@Override](https://my.oschina.net/u/1162528)
		public Object getObject() throws BeansException {
			try {
				// 匿名內部類中建立bean對象
				return createBean(beanName, mbd, args);
			}
			catch (BeansException ex) {
				// Explicitly remove instance from singleton cache: It might have been put there
				// eagerly by the creation process, to allow for circular reference resolution.
				// Also remove any beans that received a temporary reference to the bean.
				destroySingleton(beanName);
				throw ex;
			}
		}
	});
	// 處理FactoryBean擴展
	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

能夠看到,對象建立完成後會判斷是否爲FactoryBean的子類,若是是,則會調用getObject方法返回真正的對象。編碼

2.ProxyFactoryBean實現

回到ProxyFactoryBean,先貼出以前例子的配置。.net

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
	http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
	
	<!-- 原始對象 -->
	<bean id="chromeBrowser" class="com.lcifn.spring.aop.bean.ChromeBrowser"/>
	<!-- 環繞加強對象 -->
	<bean id="browserAroundAdvice" class="com.lcifn.spring.aop.advice.BrowserAroundAdvice"></bean>
	
	<bean id="browserProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<!-- 接口 -->
		<property name="interfaces" value="com.lcifn.spring.aop.bean.Browser"/>
		<!-- 要代理的對象 -->
		<property name="target" ref="chromeBrowser"/>
		<!-- 攔截器組 -->
		<property name="interceptorNames">
			<list>
				<value>browserAroundAdvice</value>
			</list>
		</property>
	</bean>
</beans>

基本配置就不說了,按照上面FactoryBean的介紹,Spring建立完ProxyFactoryBean對象後,就會調用其getObject方法。prototype

public Object getObject() throws BeansException {
	// 初始化Advisor鏈
	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();
	}
}

getObject方法就作了兩件事,一是初始化Advisor鏈,二是建立代理對象,不過建立代理對象時區分單例和多例。設計

初始化Advisor鏈

簡單地說,就是將配置中的interceptorNames轉化成Advisor對象。其中又分爲名稱精確匹配和名稱全局匹配兩種,精確匹配就不用說了,全局匹配就是以*號結尾的這種。

對於全局匹配這種,就是在BeanFactory中匹配全部Advisor和Interceptor類型的Bean,再用*前的名稱前綴去匹配Bean的名稱。

private void addGlobalAdvisor(ListableBeanFactory beanFactory, String prefix) {
	String[] globalAdvisorNames =
			BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Advisor.class);
	String[] globalInterceptorNames =
			BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Interceptor.class);
	List<Object> beans = new ArrayList<Object>(globalAdvisorNames.length + globalInterceptorNames.length);
	Map<Object, String> names = new HashMap<Object, String>(beans.size());
	for (String name : globalAdvisorNames) {
		Object bean = beanFactory.getBean(name);
		beans.add(bean);
		names.put(bean, name);
	}
	for (String name : globalInterceptorNames) {
		Object bean = beanFactory.getBean(name);
		beans.add(bean);
		names.put(bean, name);
	}
	OrderComparator.sort(beans);
	for (Object bean : beans) {
		String name = names.get(bean);
		if (name.startsWith(prefix)) {
			addAdvisorOnChainCreation(bean, name);
		}
	}
}

而對於精確匹配的更加清晰,直接取BeanFactory中找,而若是ProxyFactoryBean的singleton屬性設置爲false時,則封裝爲PrototypePlaceholderAdvisor延遲建立。

// If we get here, we need to add a named interceptor.
// We must check if it's a singleton or prototype.
Object advice;
if (this.singleton || this.beanFactory.isSingleton(name)) {
	// Add the real Advisor/Advice to the chain.
	advice = this.beanFactory.getBean(name);
}
else {
	// It's a prototype Advice or Advisor: replace with a prototype.
	// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
	advice = new PrototypePlaceholderAdvisor(name);
}
addAdvisorOnChainCreation(advice, name);

兩種方式最後都經過addAdvisorOnChainCreation來執行添加操做。其中重要的是將根據name從BeanFactory中得到的對象轉換成Advisor,由於interceptorNames支持Advisor,Advice,MethodInterceptor多種類型的對象name,經過namedBeanToAdvisor方法統一轉成Advisor類型。

private void addAdvisorOnChainCreation(Object next, String name) {
	// We need to convert to an Advisor if necessary so that our source reference
	// matches what we find from superclass interceptors.
	// 轉換Bean對象爲Advisor
	Advisor advisor = namedBeanToAdvisor(next);
	if (logger.isTraceEnabled()) {
		logger.trace("Adding advisor with name '" + name + "'");
	}
	addAdvisor(advisor);
}

private Advisor namedBeanToAdvisor(Object next) {
	try {
		return this.advisorAdapterRegistry.wrap(next);
	}
	catch (UnknownAdviceTypeException ex) {
		// We expected this to be an Advisor or Advice,
		// but it wasn't. This is a configuration error.
		throw new AopConfigException("Unknown advisor type " + next.getClass() +
				"; Can only include Advisor or Advice type beans in interceptorNames chain except for last entry," +
				"which may also be target or TargetSource", ex);
	}
}

這裏的advisorAdapterRegistry實現爲DefaultAdvisorAdapterRegistry,這個wrap方法也是被多個地方調用以達到統一Advisor,以後方便生成代理攔截器鏈。

public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
	if (adviceObject instanceof Advisor) {
		return (Advisor) adviceObject;
	}
	if (!(adviceObject instanceof Advice)) {
		throw new UnknownAdviceTypeException(adviceObject);
	}
	Advice advice = (Advice) adviceObject;
	if (advice instanceof MethodInterceptor) {
		// So well-known it doesn't even need an adapter.
		return new DefaultPointcutAdvisor(advice);
	}
	for (AdvisorAdapter adapter : this.adapters) {
		// Check that it is supported.
		if (adapter.supportsAdvice(advice)) {
			return new DefaultPointcutAdvisor(advice);
		}
	}
	throw new UnknownAdviceTypeException(advice);
}

建立代理對象

建立代理對象時根據singleton屬性決定建立的對象是單例仍是多例。咱們以單例的來看

private synchronized Object getSingletonInstance() {
	if (this.singletonInstance == null) {
		// 返回targetSource
		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;
}

freshTargetSource判斷targetName爲null,直接返回targetSource,不然從beanFactory根據targetName獲取target對象。

對於代理接口集合爲空,且proxyTargetClass爲空時,從targetClass獲取其實現的接口集合做爲代理接口。於是在配置ProxyFactoryBean時,能夠不用指定interfaces屬性。

getProxy方法的實現同ProxyFactory一致,都是經過AopProxyFactory->AopProxy->Proxy的方式,具體可見ProxyFactory中的建立代理一節。返回的對象賦予類變量做爲單例緩存。

對於多例的狀況,調用的newPrototypeInstance方法

private synchronized Object newPrototypeInstance() {

	ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());
	// The copy needs a fresh advisor chain, and a fresh TargetSource.
	TargetSource targetSource = freshTargetSource();
	copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain());
	if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
		// Rely on AOP infrastructure to tell us what interfaces to proxy.
		copy.setInterfaces(
				ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass(), this.proxyClassLoader));
	}
	copy.setFrozen(this.freezeProxy);

	if (logger.isTraceEnabled()) {
		logger.trace("Using ProxyCreatorSupport copy: " + copy);
	}
	return getProxy(copy.createAopProxy());
}

經過建立一個新的基類對象ProxyCreatorSupport,並copy全部配置的方式每次生成一個新的對象,最後經過getProxy方法獲取代理對象。

至此ProxyFactoryBean的介紹就結束了,它主要的特色就是使用FactoryBean同IOC進行告終合。你們都知道Spring框架是一種微內核的設計,包括其AOP,事務管理等許多功能都是經過擴展的方式來設計的。而這種設計思想隨着深刻到各功能源碼,包括一些其餘框架同Spring的整合,不能不說這是Spring生態繁榮的一個重要緣由。

相關文章
相關標籤/搜索