先了解一些AOP的概念:
1.Advice(通知)
定义在连接点做什么,为切面增强提供织入接口。比如BeforeAdvice,AfterAdvice等。可以定义在方法执行前或执行后需要做的操作。
2.Pointcut(切点)
定义Advice通知应该作用于哪个连接点。
比如这个JdkRegexpMethodPointcut,就是通过正则表达式是否匹配来判断是否作用于这个Adivce的。
3.Advisor(通知器)
Advisor是Advice和Pointcut的结合,定义了应该使用哪个Advice,并且定义了在哪个Pointcut使用。也就是说,定义了在哪个条件用哪个Advice。
Spring AOP的实现,用到了动态代理,所以还要对动态代理有个了解,我之前在一篇帖子中也总结过JDK动态代理的用法:动态代理总结
Java已经提供了Proxy类,一般情况下,我们通过Proxy.newProxyInstance方法,就可以创建一个代理对象了。
那Spring AOP的原理是啥呢,我们定义了Advisor之后,如何起作用呢。
先说下结论吧,我们用了Advisor,来定义了我们要为某个类在满足某些条件的时候增强,当我们在使用这个类的对象时候,Spring AOP就会为这个类生成一个代理对象,并且把我们在Advice里面定义的操作都封装成一个个的拦截器,当我们调用方法的时候,就会先经过这些拦截器,然后再通过反射来调用真正的方法。
Spring AOP模块关于生成代理对象时,会涉及到下面这些类。
对于需要使用AspectJ的AOP应用,AspectJProxyFactory就可以集成Spring和AspectJ,对于使用Spring AOP的应用,ProxyFactoryBean和ProxyFactory都提供了AOP的封装,不同的是,ProxyFactoryBean可以在IoC容器中完成声明式的配置,而ProxyFactory需要编程式的使用。
接下来看下ProxyFactoryBean,使用ProxyFactoryBean之前需要配置,定义使用的通知器Advisor,定义target等,这里就不再详细说明,关键去看代码。
接下来,看一下ProxyFactoryBean如何生成代理对象的,看ProxyFactoryBean类的代码,很明显可以看到一个getObject方法,注释写的是返回一个proxy,那就是它了:
/**
* Return a proxy. Invoked when clients obtain beans from this factory bean.
* Create an instance of the AOP proxy to be returned by this factory.
* The instance will be cached for a singleton, and create on each call to
* {@code getObject()} for a proxy.
* @return a fresh AOP proxy reflecting the current state of this factory
*/
@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();
}
}
getObject里面,能够看到主要有三个方法,第一个是initializeAdvisorChain,这个是初始化Advisor链的,接下来,还需要判断一下,对于singleton和prototype来说,需要调用不同的方法来生成proxy。
那就先看下initializeAdvisorChain的逻辑:
/**
* Create the advisor (interceptor) chain. Advisors that are sourced
* from a BeanFactory will be refreshed each time a new prototype instance
* is added. Interceptors added programmatically through the factory API
* are unaffected by such changes.
*/
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.isS