CglibAopProxy DynamicAdvisedInterceptor

最近新公司在用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);

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

@, {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;}// . // “…(target != null) {targetClass = target.getClass();}List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);Object retVal;(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);}}}

代码看起来很简单。 下面我们可以逐行对代码进行分析。 方法签名:

) 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(, 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 final Method method;hashCode;public MethodCacheKey(Method method) {this.method = method;this.hashCode = method.hashCode();}(Object other) {if (other == this) {return true;}MethodCacheKey otherKey = (MethodCacheKey) other;return (this.method == otherKey.method);}() {return this.hashCode;}}}

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

List<Object> cached = this.methodCache.get(cacheKey);Map<MethodCacheKey, List<Object>> methodCache;

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

if (cached == null) {cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);this.methodCache.put(cacheKey, cached);}@Overridepublic 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()) {(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()用积极的拼搏迎接雨后的彩虹,相信自己

CglibAopProxy DynamicAdvisedInterceptor

相关文章:

你感兴趣的文章:

标签云: