接上文,前面说了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
完成的工作看起来很简单,需要将advisor
和targetbean
织入就会完成既定的工作。但我们之前说过,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
我们在运行时,通过日志不难发现其地处分别使用的是JdkDynamicAopProxy
和Cglib2AopProxy
。下面通过SpringAOP中的整体结构来看看其运行的原理。
在SpringAOP中,有一个AopProxy
是作为其”根”,有两个实现类来完成实际的工作,没错就是上面的两个家伙。而同时又通过工厂模式AopProxyFactory
对AopProxy
的实例进行封装:
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
而非上面讲述的AopProxy
或AdvisedSupport
?是的,我们来看看下图:
从上图可以很明显看到ProxyFactory
继承自ProxyCreatorSupport
,而后者提供了生成AopProxy
的方法
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
而他同时继承了AdvisedSupport
,那么我们对这个链上的都可以获取到了