博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
AOP源码分析-CglibAopProxy DynamicAdvisedInterceptor
阅读量:5143 次
发布时间:2019-06-13

本文共 9416 字,大约阅读时间需要 31 分钟。

最近新公司在用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 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 chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);    public List getInterceptorsAndDynamicInterceptionAdvice(Method method, Class
targetClass) { MethodCacheKey cacheKey = new MethodCacheKey(method); List 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 cached = this.methodCache.get(cacheKey);    /** Cache with Method as key and advisor chain List as value */    private transient Map
> methodCache;

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

if (cached == null) {            cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(                    this, method, targetClass);            this.methodCache.put(cacheKey, cached);        }@Override    public List 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 interceptorList = new ArrayList(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;

转载于:https://www.cnblogs.com/jingLongJun/p/4491037.html

你可能感兴趣的文章
开启GD拓展
查看>>
JQUERY 大于
查看>>
ZooKeeper做独立server执行(上)
查看>>
《经济地理与企业兴衰》学习笔记
查看>>
正确 C# 未来的期望
查看>>
树状数组
查看>>
POJ 1328 Radar Installation(经典贪婪)
查看>>
Netty源代码学习——EventLoopGroup原理:NioEventLoopGroup分析
查看>>
IOS status bar
查看>>
void及void指针含义的深刻解析
查看>>
【UVA】434-Matty's Blocks
查看>>
五、宽度优先搜索(BFS)
查看>>
运行一个窗体直接最大化并把窗体右上角的最大化最小化置灰
查看>>
Android开发技术周报 Issue#80
查看>>
hadoop2.2.0+hive-0.10.0完全分布式安装方法
查看>>
WebForm——IIS服务器、开发方式和简单基础
查看>>
小实验3:实现haproxy的增、删、查
查看>>
Java集合类学习笔记(各种线性表性能分析)
查看>>
eclipse git 拉取内容
查看>>
FCKEditor网页编辑器
查看>>