Spring AOP的Aspect与织入原理 spring

接上文,前面说了SpringAOP中Joinpoint,Pointcut,Advice的相关概念和常见类型,下面就是将这些元素整合在一起work的步骤了,这就是
## Aspect ## 在SpringAOP中,主要用Advisor来描述这一概念:

public interface PointcutAdvisor extends Advisor {

	Pointcut getPointcut();

}

作为一些常用的advisor可见UML:

1、DefaultPointcutAdvisor
这是最通用的实现,可以对除Introduction类外的任何Pointcut、Advice来使用。使用也很简单,在构造函数的时候就可以指定:

public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {
	this.pointcut = pointcut;
	setAdvice(advice);
}

当然也有提供getter/setter方法来获取相应的Pointcut、Advice

DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
advisor.setAdvice(advice);
advisor.setPointcut(pointcut);

2、NameMatchMethodPointcutAdvisor
很显然,从名字来看这个是为NameMatchMethodPointcut准备的,在实例时也只提供了对Advice的支持,当然除了Introduction外任何类型的advice都支持了

public NameMatchMethodPointcutAdvisor(Advice advice) {
	setAdvice(advice);
}

使用这个advisor后我们就不必再去维护mapper了,因为已经有提供:

public void setMappedName(String mappedName) {
	this.pointcut.setMappedName(mappedName);
}

public void setMappedNames(String[] mappedNames) {
	this.pointcut.setMappedNames(mappedNames);
}

3、RegexpMethodPointcutAdvisor
与前者类似,这里也是专为regexp准备,这里维护了一个

private AbstractRegexpMethodPointcut pointcut;

而这就涉及我们之前讲过的两种正则支持:

JdkRegexpMethodPointcut
Perl5RegexpMethodPointcut(3.1后已经没有)

用法与其他类似不再多做介绍

4、DefaultBeanFactoryPointcutAdvisor
这是与SpringIOC容器相关的advisor,功能都类似,只是需要在容器中注入。当然前面介绍的几种也可以使用容器注入的方式进行设置。

5、Order
从前面的UML图中可以看到,在顶层的抽象AbstractPointcutAdvisor实现了Order接口,如果存在多个Pointcut时可以通过设定单独的order来指定执行顺序,值越小将最先被执行

织入

前面几部分分别介绍了AOP涉及的几个部分,现在是将各个部分整合在一起工作的时候了。在SpringAOP中主要使用了ProxyFactory来完成这部分工作。以一个简单的例子来说明这个过程:

ComposablePointcut pc = new ComposablePointcut(ClassFilter.TRUE, new FooMethodMatcher());
//新增一个Pointcut:两个只需要其中一个为TRUE即可
pc.union(new BarMethodMatcher());

Advisor advisor = new DefaultPointcutAdvisor(pc, new SimpleBeforeAdvice());

ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.addAdvisor(advisor);
proxyFactory.setTarget(new SimpleBean());

SimpleBean proxyBean = (SimpleBean) proxyFactory.getProxy();

proxyBean.sayHi("Robin");
proxyBean.sayHi();
proxyBean.greet();

ProxyFactory完成的工作看起来很简单,需要将advisortargetbean织入就会完成既定的工作。但我们之前说过,SpringAOP对接口和类采用了不同的代理机制,他们分别是什么,已经如何决定实际需要的factory?
我们首先来看看编程式如何完成对接口和类的代理:
1、JDK动态代理接口

ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.addAdvisor(advisor);
proxyFactory.setTarget(new GreetBeanImpl());
proxyFactory.setInterfaces(new Class[] { GreetBean.class });
GreetBean proxyBean = (GreetBean) proxyFactory.getProxy();

其中GreetBean是接口,GreetBeanImpl是其实现类,下同

2、Cglib代理类

ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.addAdvisor(advisor);
proxyFactory.setTarget(new GreetBeanImpl());
GreetBean proxyBean = (GreetBean) proxyFactory.getProxy();

要想这能跑起来需要相应的cglib在你classpath

我们在运行时,通过日志不难发现其地处分别使用的是JdkDynamicAopProxyCglib2AopProxy。下面通过SpringAOP中的整体结构来看看其运行的原理。

在SpringAOP中,有一个AopProxy是作为其”根”,有两个实现类来完成实际的工作,没错就是上面的两个家伙。而同时又通过工厂模式AopProxyFactoryAopProxy的实例进行封装:

public interface AopProxyFactory {

	/**
	 * Create an {@link AopProxy} for the given AOP configuration.
	 * @param config the AOP configuration in the form of an
	 * AdvisedSupport object
	 * @return the corresponding AOP proxy
	 * @throws AopConfigException if the configuration is invalid
	 */
	AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;

}

AopProxyFactory会根据传入的AdvisedSupport来觉得用什么类型的AopProxy,看看他的实现类DefaultAopProxyFactory的具体方法:

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);
		}
		if (!cglibAvailable) {
			throw new AopConfigException(
					"Cannot proxy target class because CGLIB2 is not available. " +
					"Add CGLIB to the class path or specify proxy interfaces.");
		}
		return CglibProxyFactory.createCglibProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}

从上面的代码看出是根据AdvisedSupport来判断采用何种具体的实现代理。而AdvisedSupport又做了什么?

从上图可以看到:
1、继承了ProxyConfig,主要描述生成代理对象的控制信息:

//代理目标对象是否为class
private boolean proxyTargetClass = false;
//代理对象是否需要进一步优化:如代理对象生成后不再修改等,如果为true会采用cglib生成代理对象
private boolean optimize = false;
//生成的代理对象是否可强制转换为Advised
boolean opaque = false;
//是否将当前生成的代理对象绑定到ThreadLocal
boolean exposeProxy = false;
//如果为true,一旦生成代理对象后将不再改变
private boolean frozen = false;

2、实现Advised接口,用来承载生成代理对象所需要的目标类、Advice、Advisor等。从源代码可以看到这个接口定义了一些列获取、设置上述对象的方法。

回到最开始的问题,我们有个疑问在整合的时候是采用的ProxyFactory而非上面讲述的AopProxyAdvisedSupport?是的,我们来看看下图:

从上图可以很明显看到ProxyFactory继承自ProxyCreatorSupport,而后者提供了生成AopProxy的方法

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

而他同时继承了AdvisedSupport,那么我们对这个链上的都可以获取到了



blog comments powered by Disqus