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;
相关文章推荐
- 浅析Spring AOP源码(十四) 分析ProxyFactoryBean
- 浅析Spring AOP源码(十五) 分析JdkDynamicAopProxy的invoke方法
- JdkDynamicAopProxy源码
- 做一个合格的程序猿之浅析Spring AOP源码(十四) 分析ProxyFactoryBean
- Spring源码分析之ProxyFactoryBean方式实现Aop功能的分析
- ProxyFactoryBean 实现 Aop 功能源码分析
- Spring @Transactional注解出错:CglibAopProxy - Unable to apply any optimisations to advised method < >
- 【原创】OpenStack Swift源码分析(三)proxy服务启动
- Spring 源码分析(三) —— AOP(一)AOP原理
- AOP:PostSharp和Castle DynamicProxy
- spring源码分析,重新认识spring 二(aop实现详细分析)
- Spring源码分析——AOP实现(2)
- Spring的AOP实现方式—ProxyFactoryBean配置方式实现源码剖析
- Mongodb 源码分析--Replication之OpLog
- Spring AOP 源码分析 - 创建代理对象
- Spring源码分析----建立AopProxy代理对象和AOP拦截器的调用
- Spring源码分析:AOP源码解析(上篇)
- Spring源码解析-AOP简单分析
- 基于Spring源码分析AOP的实现机制
- 理解Spring AOP 原理(三)Spring AOP 源码分析