Spring源码-AOP(五)-ProxyFactoryBean

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,它是Spring AOP核心的底层实现。然而硬编码的方式还是过于繁琐且不易使用,本章我们将讨论ProxyFactoryBean,它结合了ProxyFactory和Ioc中的FactoryBean扩展,使得可以通过XML配置的方式来实现Spring AOP。关于Spring AOP创建代理的具体实现本章将不会再赘述,而是主要讨论FactoryBean扩展结合Spring AOP的使用。

1.FactoryBean简介

我在IOC容器(四)-FactoryBean一篇中已详细地介绍了FactoryBean在Spring IOC中的实现原理,这里还是简单介绍一下。

FactoryBean顾名思义,工厂Bean,即可以动态创建Bean的Bean。对于一些只有在运行时才能明确的对象来说,直接在XML中定义已不能满足,而是通过定义一个工厂类,在运行时根据不同配置来生成最终的对象。

FactoryBean是Spring IOC的两大扩展之一(另一个是BeanPostProcessor),由此与Spring集成的功能众多,包括但不限于AOP,ORM,事务管理,Remoting。

简单看下AbstractBeanFactory中对FactoryBean处理的代码

// 单例
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,先贴出之前例子的配置。

<?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方法。

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生态繁荣的一个重要原因。

转载于:https://my.oschina.net/u/2377110/blog/1512222

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值