JDK动态代理与CGLIB动态代理
Spring AOP的主要工作就是将Advice和Target结合生成代理对象(不同的是AspectJ是在字节码层面织入的,JVM类加载的就是经过增强的对象,而不需要代理模式)。其主要逻辑可大体拆分为两部分:
以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代理。其中JDK代理由JdkDynamicAopProxy类支持,CGLIB代理由CglibAopProxy支持。
JdkDynamicAopProxy类实现了InvocationHandler接口,在其Invoke方法里实现了Advice的织入。
invoke方法里有两个重要的地方:MethodInterceptor链的生成和增强方法的调用逻辑
List
这一步由DefaultAdvisorChainFactory支持,该工厂方法用于从Advisor链生成某个方法的MethodInterceptor链。这里主要有两部分内容:
前面我们讲到GlobalAdvisorAdapterRegistry将IOC容器中的InterceptorNames对应的Bean封装为Advisor,后来,从Advisor拆出Advice并依据其类型创建对应的MethodInterceptor
@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List interceptors = new ArrayList(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 技术内幕