博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
深入理解Spring AOP实现
阅读量:4223 次
发布时间:2019-05-26

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

总所周知,Spring通过动态代理的方式实现AOP处理,那么当我们调用一个被AOP处理的方法,其内部是如何实现的呢?

我们以Jdk动态代理为例,当我们访问代理对象到最后访问目标方法,JdkDynamicAopProxy采用了如下步骤:

  • 调用Proxy.newProxyInstance()生成JdkDynamicAopProxy对象
  • 调用该对象的invoke()方法;
  • 然后匹配通知类型调用通知(通知就是@Before、@After等等);
  • 最后调用目标方法。

Jdk动态代理使用getProxy方法获取代理对象,进入getProxy方法:

public Object getProxy(ClassLoader classLoader) {        if (logger.isDebugEnabled()) {            logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());        }        Class
[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised); this.findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }
  • classloader:类加载器,定义了由哪个ClassLoader对象来对生成的代理对象进行加载

  • proxiedInterfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口

  • this:表示JdkDynamicAopProxy自身,因为JdkDynamicAopProxy实现了InvocationHandler接口

调用代理对象的invoke方法,进入invoke方法:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                …………                //获取拦截器链                List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);                if (chain.isEmpty()) {                    //直接调用target的对应方法                    retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);                } else {                    //先调用拦截器,再调用目标方法                    MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);                    retVal = invocation.proceed();                }                …………    }

匹配通知类型调用通知

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); boolean hasIntroductions = hasMatchingIntroductions(config, targetClass); 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(targetClass)) { MethodInterceptor[] interceptors = registry.getInterceptors(advisor); MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); if (MethodMatchers.matches(mm, method, targetClass, 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(targetClass)) { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } else { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; }

这里先获取拦截器链,跟踪getInterceptorsAndDynamicInterceptionAdvice方法,其实此处使用了适配器的设计模式,将配置的通知Advisor转化成拦截器Interceptor。

调用目标方法

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);        }    }

可以看到,此处循环调用processd方法,如果currentInterceptorIndex =-1,表示所有的拦截器调用完毕,接下来调用目标方法。

适配器模式

  • 将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。——Gang of Four

转载地址:http://usgmi.baihongyu.com/

你可能感兴趣的文章
【一天一道LeetCode】#45. Jump Game II
查看>>
终端驱动程序:几个简单例子
查看>>
HTML条件注释
查看>>
内核态与用户态
查看>>
趣链 BitXHub跨链平台 (4)跨链网关“初介绍”
查看>>
C++ 字符串string操作
查看>>
MySQL必知必会 -- 了解SQL和MySQL
查看>>
MySQL必知必会 -- 排序检索数据 ORDER BY
查看>>
POJ 1154 解题报告
查看>>
POJ 1101 解题报告
查看>>
ACM POJ catalogues[转载]
查看>>
常见的排序算法
查看>>
hdu 3460 Ancient Printer(trie tree)
查看>>
DAG以及任务调度
查看>>
LeetCode——DFS
查看>>
MapReduce Task数目划分
查看>>
3126 Prime Path
查看>>
app自动化测试---ADBInterface驱动安装失败问题:
查看>>
九度OJ 1091:棋盘游戏 (DP、BFS、DFS、剪枝)
查看>>
c++使用宏检测类是否包含某个函数或者变量属性
查看>>