您的位置:首页 > 运维架构

AOP源码分析-CglibAopProxy DynamicAdvisedInterceptor

2015-04-24 11:33 453 查看
最近新公司在用Spring MVC,跟踪Spring的Service发现是通过动态代理来实现的,而公司的事务是配置在Service层。所以想看下Spring 的AOP的具体实现。本文源码基于Spring 4.0。


我们可以使用debug跟踪一次Service调用的整体流程,可以清晰的看到一次流程处理:

CglibAopProxy.intercept方法,该方法中通过

this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);


获取一个List拦截链,然后通过

retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();


方法执行对应的拦截链进行执行处理。

最后通过,

processReturnType(proxy, target, method, retVal);


处理返回值,并返回。

整体过程完全采用动态代理模式来实现。最主要的代码如下:

@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; }
// May be null. Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool...
target = getTarget(); if (target != null) { targetClass = target.getClass(); }
List<Object> chain =this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// 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 = methodProxy.invoke(target, args);
}
else {
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal =processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}


代码看起来很简单。

下面我们可以逐行对代码进行分析。

方法签名:

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable


可以看出,改方法传入代理对象,方法对象,参数以及方法代理。MethodProxy 包含我们的需要被代理的方法信息,包含方法完整签名。

if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}


此处代码是判断代理是否可用,大概是这个意思,此处的代码不是很明白。

target = getTarget();
if (target != null) {
targetClass = target.getClass();
}


此处是获取目标类对象。

下来是获取对应的链对象。

List<Object> chain =this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}


在这个方法中,比较重要的应该是cacheKey的获取。

/**
* Simple wrapper class around a Method. Used as the key when
* caching methods, for efficient equals and hashCode comparisons.
*/
private static class MethodCacheKey {
private final Method method;
private final int hashCode;
public MethodCacheKey(Method method) {
this.method = method;
this.hashCode = method.hashCode();
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
MethodCacheKey otherKey = (MethodCacheKey) other;
return (this.method == otherKey.method);
}
@Override
public int hashCode() {
return this.hashCode;
}
}
}


这个类比较简单,定义了对应的Method对象,以及Method对应的hashCode。

List<Object> cached = this.methodCache.get(cacheKey);
/** Cache with Method as key and advisor chain List as value */
private transient Map<MethodCacheKey, List<Object>> methodCache;


此处缓存了对应的拦截器链。如果为null,则通过factory实例化,并放入缓存。

if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}


这个方法虽然很长,但是实际内容还是相对比较简单。

首先获取所有切点。

config.getAdvisors()


判断不同的切点类型,放入List。

执行对应List方法。

retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

@Override
public Object proceed() throws Throwable {
//  We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
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.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}


处理返回值:

retVal =processReturnType(proxy, target, method, retVal);
return retVal;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: