文档章节

Spring源码阅读-使用ProxyFactoryBean实现AOP

Small-Liu
 Small-Liu
发布于 2017/07/03 16:51
字数 1275
阅读 125
收藏 0

一 例子

通过ProxyFactoryBean实现对Person的代理,不需要修改代码Person,只需要配置:

public interface IPerson {
	public String queryName();
}

public class Person implements IPerson {

	private String name;
	
	public String queryName() {
		System.out.println("name:" + name);
		return name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}
public class PersonAdvice implements MethodBeforeAdvice, AfterReturningAdvice {

	@Override
	public void before(Method method, Object[] args, Object target) throws Throwable {
		System.out.println("before......");
	}

	@Override
	public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
		System.out.println("afterReturning......");
	}
}
<bean id="person" class="com.myframe.modules.test.service.impl.Person">
	<property name="name" value="zhangsan"></property>
</bean> 

<!-- 准备切点跟advice -->
<bean id="beforeAfterAdvice" class="com.myframe.modules.test.service.impl.PersonAdvice">
</bean>
<bean id="queryPointCut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
	<property name="pattern" value=".*query.*"></property>
</bean>
<bean id="queryAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
	<property name="advice" ref="beforeAfterAdvice"></property>
	<property name="pointcut" ref="queryPointCut"></property>
</bean>

<bean id="personProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
	<property name="target" ref="person"/>  
 	<property name="interceptorNames" value="queryAdvisor" />  
</bean>

指定ProxyFactoryBean对象名称为personProxy,并指定目标对象和拦截对象,获取的personProxy对象实际上就是一个代理过的对象,调用其方法queryName的到打印结果:

before......
name:zhangsan
afterReturning......

二 源码走读

回顾前面的BeanFactory,获取personProxy对象走到doGetBean方法,doGetBean中获得对象后都会调用一句getObjectForBeanInstance方法,这里是实现代理的核心逻辑,它的核心思想是判断对象是否是FactoryBean,如果是则调用其getObject方法。

上面使用的ProxyFactoryBean是FactoryBean的子类,看它的getObject方法:

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

主要分两步:

1. initializeAdvisorChain

private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
	if (this.advisorChainInitialized) {
		return;
	}
	if (!ObjectUtils.isEmpty(this.interceptorNames)) {
		if (this.beanFactory == null) {
			throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) "
					+ "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
		}
		// Globals can't be last unless we specified a targetSource using
		// the property...
		if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX)
				&& this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
			throw new AopConfigException("Target required after globals");
		}
		// Materialize interceptor chain from bean names.
		for (String name : this.interceptorNames) {
			if (logger.isTraceEnabled()) {
				logger.trace("Configuring advisor or advice '" + name + "'");
			}
			//带通配符的, 就把容器中所有命中的都拿出来
			if (name.endsWith(GLOBAL_SUFFIX)) {
				if (!(this.beanFactory instanceof ListableBeanFactory)) {
					throw new AopConfigException(
							"Can only use global advisors or interceptors with a ListableBeanFactory");
				}
				addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
						name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
			}
			else {
				// 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);
			}
		}
	}
	this.advisorChainInitialized = true;
}

这边就是将配置的interceptorNames对应的对象初始化好放到advisors集合中,如果带有*结尾的就把beanFactory中所有命中的前缀都加进来,advisorChainInitialized会标记是否已经处理过,保证只会被加载一次。   

2. 实例化

这里以单例模式看代理对象的创建,看方法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);
		//先获取aop proxy对象
		this.singletonInstance = getProxy(createAopProxy());
	}
	return this.singletonInstance;
}
protected final synchronized AopProxy createAopProxy() {
	if (!this.active) {
		activate();
	}
	//先获取创建AopProxy的工厂, 再由此创建AopProxy
	return getAopProxyFactory().createAopProxy(this);
}

根据方法调用可以看出先获取AopProxyFactory,然后创建AopProxy,再通过AopProxy创建代理对象。

AopProxyFactory默认就一个实现DefaultAopProxyFactory,看它的createAopProxy方法:

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()) {
			return new JdkDynamicAopProxy(config);
		}
		return new ObjenesisCglibAopProxy(config);
	} else {
		return new JdkDynamicAopProxy(config);
	}
}

这个地方就看出spring是分别什么条件下使用jdk或cglib的动态代理了,总结如下:

  • 如果目标对象实现了接口,默认用jdk proxy,也可以通过配置指定使用cglib
  • 如果目标对象没有实现接口,必须用cglib

下面就是根据两种AopProxy创建代理对象的逻辑了:

如果返回的是JdkDynamicAopProxy则创建代理的方法:

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

@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);
	findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
	//标准的jdk proxy用法
	return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

如果返回的是ObjenesisCglibAopProxy则创建代理的方法:

@Override
public Object getProxy() {
	return getProxy(null);
}

@Override
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);
		//创建配置Enhancer
		// Configure CGLIB 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.
		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);
	}
}

这就是用cglib创建代理对象的范畴了。

© 著作权归作者所有

Small-Liu
粉丝 17
博文 56
码字总数 49976
作品 0
南京
程序员
私信 提问
用ProxyFactoryBean创建AOP代理

用ProxyFactoryBean创建AOP代理 使用Spring提供的类org.springframework.aop.framework.ProxyFactoryBean是创建AOP的最基本的方式 。 使用 ProxyFactoryBean 来创建 AOP 代理的最重要的优点之...

嘻哈开发者
2015/07/02
0
0
Spring AOP介绍及源码分析

一、AOP介绍 举个例子来说明一下吧!现在系统中有很多的业务方法,如上传产品信息、修改产品信息、发布公司库等;现在需要对这些方法的执行做性能监控,看每个业务方法的执行时间;在不改变原...

阿扬丶
2013/11/07
0
3
深入解析Spring架构与设计原理-AOP

关于AOP的个人理解 AOP联盟定义的AOP体系结构把与AOP相关的概念大致分为了由高到低、从使用到实现的三个层次。关于这个体系结构,个人的理解是这样的,从上往下,最高层是语言和开发环境,在...

Java小铺
2018/08/27
0
0
Spring3.2 AOP 分析

Spring3.2 AOP个人分析: AOP, 即Aspect-Oriented-Programming, 面向切面编程, 又一Spring的核心,被广泛应用,如在Spring-tx中都有用到,其好处是实现松耦合的外围处理程序,先说些理论吧。...

ihaolin
2014/01/17
0
0
Spring API级别对AOP的支持

在Spring 2.0之前,Spring通过定义一套接口和通过ProxyFactoryBean来生产bean实例提供对AOP的支持,在2.0后,Spring推荐通过AspectJ兼容的方式来实现AOP.见http://blog.csdn.net/kkdelta/archiv...

晨曦之光
2012/04/25
339
0

没有更多内容

加载失败,请刷新页面

加载更多

Android双向绑定原理简述

Android双向绑定原理简述 双向绑定涉及两个部分,即将业务状态的变化传递给UI,以及将用户输入信息传递给业务模型。 首先我们来看业务状态是如何传递给UI的。开启dataBinding后,编译器为布局...

tommwq
今天
2
0
Spring系列教程八: Spring实现事务的两种方式

一、 Spring事务概念: 事务是一系列的动作,它们综合在一起才是一个完整的工作单元,这些动作必须全部完成,如果有一个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发生过一样。...

我叫小糖主
今天
6
0
CentOS 的基本使用

1. 使用 sudo 命令, 可以以 root 身份执行命令, 必须要在 /etc/sudoers 中定义普通用户 2. 设置 阿里云 yum 镜像, 参考 https://opsx.alibaba.com/mirror # 备份mv /etc/yum.repos.d/CentO...

北漂的我
昨天
3
0
Proxmox VE技巧 移除PVE “没有有效订阅” 的弹窗提示

登陆的时候提示没有有效的订阅You do not have a valid subscription for this server. Please visit www.proxmox.com to get a list of available options. 用的是免费版的,所以每次都提示......

以谁为师
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部