Spring AOP
相关概念
- AOP:Aspect-Oriented Programming,是一种新的模块化机制,用来描述分散在对象、类或者函数中的横切关注点。
- Join Point:程序流中被分割为一个个代码单元,单元之间的点即为Join Point。如程序调用栈中,可以按照各个方法将代码执行流分割为一个个方法单元,那么方法调用前后都是Join Point。
- Advice:模块化内容,也是增强逻辑本身。
- Introduction:引介增强,向Target引入新的属性或者方法
- PointCut:关注点,将要织入Advice的Join Point的集合。
- Advisor:增强与关注点的结合,Advice+PointCut/Introduction+PointCut
- MethodInterceptor:Advice的子类,在Spring AOP中,各类Advice最终都会封装为MethodInterceptor,其invoke方法中封装了Target和Advice的相对执行顺序
- MethodInvocation:Joinpoint的子类,指对一个方法的调用。
支撑技术
实现原理
Spring AOP的主要工作就是将Advice和Target结合生成代理对象(不同的是AspectJ是在字节码层面织入的,JVM类加载的就是经过增强的对象,而不需要代理模式)。其主要逻辑可大体拆分为两部分:
- 获取Advice、Target等相关配置信息
- 生成代理对象
以ProxyFactoryBean开始分析,这个FactoryBean的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();
}
}
这是ProxyFactoryBean的继承关系图,其中AdvisedSupport父类主要持有Advice相关配置信息,ProxyCreatorSupport父类主要负责代理类的实际生成工作。
配置信息获取与初始化
ProxyFactoryBean中配置信息的获取是经由IOC容器获取的,ProxyFactoryBean有一个属性为interceptorNames,需要在IOC容器中配置设置。在此基础上,在调用getObject()方法时,进行Advisor链的初始化。
Advisor链的初始化主要分两步:
- 注册器包装
- 添加入链表
其中注册器包装由适配器注册器GlobalAdvisorAdapterRegistry类将IOC配置中的interceptor对象类型(可能是Advisor,或者Advice等)包装为Advisor类型,并过滤不支持的类型。添加入链表的操作和链表的持有交给了父类AdvisedSupport来完成。
包装代码:
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
//Bean可以是直接定义好的含有PointCut的Advisor
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
//可以是Advice的子类MethodInterceptor类型
if (advice instanceof MethodInterceptor) {
// So well-known it doesn't even need an adapter.
return new DefaultPointcutAdvisor(advice);
}
//也可以是各类Advice,如果有适配器支持即可封装,后两者封装的都是默认的PointCutAdvisor。
for (AdvisorAdapter adapter : this.adapters) {
// Check that it is supported.
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}
生成代理对象
在父类AdvisedSupport持有了Advisor链表之后,下一步即可进行代理对象的生成工作,这一步交给父类ProxyCreatorSupport来完成,该类持有DefaultAopProxyFactory代理工厂,并通过该工厂生产代理对象。主要有两种代理对象生成方式:
- JDK代理
- CGLIB代理
通常目标类是接口的情况下使用JDK代理。其中JDK代理由JdkDynamicAopProxy类支持,CGLIB代理由CglibAopProxy支持。
JdkDynamicAopProxy类实现了InvocationHandler接口,在其Invoke方法里实现了Advice的织入。
invoke方法里有两个重要的地方:MethodInterceptor链的生成和增强方法的调用逻辑
MethodInterceptor链的生成
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
这一步由DefaultAdvisorChainFactory支持,该工厂方法用于从Advisor链生成某个方法的MethodInterceptor链。这里主要有两部分内容:
- 拆出Advisor里的PointCut用于方法的匹配和过滤
- 拆出Advisor里的Advice,根据Advice的实际类型来创建对应的MethodInterceptor,并加入链表
前面我们讲到GlobalAdvisorAdapterRegistry将IOC容器中的InterceptorNames对应的Bean封装为Advisor,后来,从Advisor拆出Advice并依据其类型创建对应的MethodInterceptor
@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
Advice advice = advisor.getAdvice();
//如果本身就是子类型MethodInterceptor,向下转型即可
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
//如果只是Advice类型,通过各类AdvisorAdapter适配器来创建
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
}
以MethodBeforeAdviceAdapter为例:
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
//从Advisor中拆出Advice后重新封装为MethodBeforeAdviceInterceptor
return new MethodBeforeAdviceInterceptor(advice);
}
}
具体封装逻辑如下:
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
private MethodBeforeAdvice advice;
/**
* Create a new MethodBeforeAdviceInterceptor for the given advice.
* @param advice the MethodBeforeAdvice to wrap
*/
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
//BeforeAdvice的执行逻辑封装在这里
//MethodInvocation为一个Joinpoint,表示将要被调用的方法,这里先执行了
//BeforeAdvice的before逻辑,再继续执行Joinpoint
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}
}
增强方法的调用
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
// We need to create a method invocation...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
这一步即实际的方法调用逻辑,当该方法的Advisor链为空时,直接通过反射调用该方法。如果不为空,通过ReflectiveMethodInvocation的proceed()方法调用。ReflectiveMethodInvocation重写了MethodInvacation的proceed()方法:
@Override
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
//直到MethodInterceptor链都执行了,才直接调用当前MethodInvocation执行
return invokeJoinpoint();
}
//不然则进入MethodInterceptor的执行逻辑,这里是动态PointCut匹配
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
//MethodInterceptor的执行逻辑
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
这里ReflectiveMethodInvocation实际上代表了一个Joinpoint的调用,但是其内部包含了一个MethodInterceptor链,即各类增强逻辑。各类增强逻辑有多个,有前也右后,其前后顺序封装在各MethodInterceptor的invoke方法里了(如前面所写的MethodBeforeAdviceInterceptor),invoke方法里对MethodInvocation的递归调用使得多个MethodInterceptor的循环得以进行,非常巧妙。
关于CGLIB的增强逻辑,是在CallBack中设置了默认的DynamicAdvisedInterceptor,其intercept方法中封装的逻辑与JDK代理的invoke方法封装的逻辑大同小异,不再赘述。
总结
spring aop首先从IOC容器中获取Advice或者MethodInterceptor等,将其封装为Advisor(这一步主要目的是将Advice与PointCut相结合),最后在JDK Proxy和CGLIB Proxy的回调方法中应用PointCut匹配具体方法,并将Advisor中的Advice按类型封装为MethodInterceptor应用到目标方法的调用MethodInvocation上去。
Spring 技术内幕