Joinpoint继承层次图:

由上图可以知道的所有的接口的实现都在ReflectiveMethodInvocation这个类中。ConstructorInvocation接口只有一个方法,这个方法的实现好像是由ReflectMethodInvocation的getStaticPart()方法来实现的,具体请看源码。

现在把上面的接口和类的源码的看看,顺便做下笔记。

一、Joinpoint

这个接口表示一个一般的运行时连接点。一个运行时连接点是一个事件,这个事件发生在一个静态连接点(也就是在程序中的某一个位置)。例如:

接口的方法:

    /**
* Proceed to the next interceptor in the chain.
* <p>The implementation and the semantics of this method depends
* on the actual joinpoint type (see the children interfaces).
* @return see the children interfaces' proceed definition
* @throws Throwable if the joinpoint throws an exception
*/
Object proceed() throws Throwable;

开始拦截器链条中的下一个的拦截器。

    /**
* Return the object that holds the current joinpoint's static part.
* <p>For instance, the target object for an invocation.
* @return the object (can be null if the accessible object is static)
*/
Object getThis();

返回目标对象。

    /**
* Return the static part of this joinpoint.
* <p>The static part is an accessible object on which a chain of
* interceptors are installed.
*/
AccessibleObject getStaticPart();

返回连接点的静态部分,其实应该就是目标方法吧。(返回连接点的静态部分,静态部分就是的已经安装在拦截器链条上的可以访问的方法对象。)

二、Invocation

这个接口表示程序当中的一个调用。一个调用就是一个连接点而且可以被一个拦截器拦截。

这个接口只有一个方法:

/**
* This interface represents an invocation in the program.
*
* <p>An invocation is a joinpoint and can be intercepted by an
* interceptor.
*
* @author Rod Johnson
*/
public interface Invocation extends Joinpoint { /**
* Get the arguments as an array object.
* It is possible to change element values within this
* array to change the arguments.
* @return the argument of the invocation
*/
Object[] getArguments(); }

方法返回的是目标方法的参数。如果目标方法是无参方法,那么会返回一个Object[] 类型的长度为0的数组。

三、MethodInvocation

/**
* Description of an invocation to a method, given to an interceptor
* upon method-call.
*
* <p>A method invocation is a joinpoint and can be intercepted by a
* method interceptor.
*
* @author Rod Johnson
* @see MethodInterceptor
*/
public interface MethodInvocation extends Invocation { /**
* Get the method being called.
* <p>This method is a frienly implementation of the
* {@link Joinpoint#getStaticPart()} method (same result).
* @return the method being called
*///返回一个已经被调用的方法,其实是目标方法。
Method getMethod(); }

getMethod()方法返回的是目标方法对应的Method对象。

四、ProxyMethodInvocation

这个接口扩展了MethodInvocation接口。

接口的方法:

    /**
* Return the proxy that this method invocation was made through.
* @return the original proxy object
*/
Object getProxy();

返回原始的对象,也就是目标对象。

    /**
* Create a clone of this object. If cloning is done before {@code proceed()}
* is invoked on this object, {@code proceed()} can be invoked once per clone
* to invoke the joinpoint (and the rest of the advice chain) more than once.
* @return an invocable clone of this invocation.
* {@code proceed()} can be called once per clone.
*/
MethodInvocation invocableClone();

浅复制

    /**
* Set the arguments to be used on subsequent invocations in the any advice
* in this chain.
* @param arguments the argument array
*/
void setArguments(Object... arguments);

设置目标方法的参数值。

    /**
* Add the specified user attribute with the given value to this invocation.
* <p>Such attributes are not used within the AOP framework itself. They are
* just kept as part of the invocation object, for use in special interceptors.
* @param key the name of the attribute
* @param value the value of the attribute, or {@code null} to reset it
*/
void setUserAttribute(String key, Object value);

设置用户属性

五、ReflectiveMethodInvocation

使用反射类调用目标对象。子类可以覆盖invokeJoinpoint()方法。可以通过使用invocableClone()方法浅克隆一个调用(an invocation)来重复调用proceed()方法。而且还可以使用setUserAttribute(...)方法添加上自定义的属性到这个调用上。

这个类的属性:

    protected final Object proxy;//代理对象。

    protected final Object target;//目标对象。

    protected final Method method;//目标方法对应的Method对象。

    protected Object[] arguments;//目标方法参数。

    private final Class<?> targetClass;//目标对象的类型

    /**
* Lazily initialized map of user-specific attributes for this invocation.
*/
private Map<String, Object> userAttributes; /**
* List of MethodInterceptor and InterceptorAndDynamicMethodMatcher
* that need dynamic checks.
*/
protected final List<?> interceptorsAndDynamicMethodMatchers; /**
* Index from 0 of the current interceptor we're invoking.
* -1 until we invoke: then the current interceptor.
*/
private int currentInterceptorIndex = -1;

这个类的方法:

这个类方法也不少,挑重要的讲。

①、构造器。

    /**
* Construct a new ReflectiveMethodInvocation with the given arguments.
* @param proxy the proxy object that the invocation was made on
* @param target the target object to invoke
* @param method the method to invoke
* @param arguments the arguments to invoke the method with
* @param targetClass the target class, for MethodMatcher invocations
* @param interceptorsAndDynamicMethodMatchers interceptors that should be applied,
* along with any InterceptorAndDynamicMethodMatchers that need evaluation at runtime.
* MethodMatchers included in this struct must already have been found to have matched
* as far as was possibly statically. Passing an array might be about 10% faster,
* but would complicate the code. And it would work only for static pointcuts.
*/
protected ReflectiveMethodInvocation(
Object proxy, Object target, Method method, Object[] arguments,
Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) { this.proxy = proxy;
this.target = target;
this.targetClass = targetClass;
this.method = BridgeMethodResolver.findBridgedMethod(method);
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}

这个构造器在初始化对象时,设置了代理对象、目标对象、目标对象所属的类Calss对象、目标方法对应的Method对象、目标方法的参数、以及MethodInterceptor和InterceptorAndDynamicMethodMatcher组成的链条。

②、这是方法最重要。不管是通知方法还是目标方法,都是通过的这个方法来调用的。所以,连接点起到了一个调度的作用。

    @Override
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
//currentInterceptorIndex的值等于拦截器链的长度的时候说明每个拦截器都被调用了。此时可以调用目标方法了。
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();//调用目标方法,不知道这里的方法名为什么叫invokeJoinpoint,明明是调用的目标方法嘛,还没参透。
} //currentInterceptorIndex的初始值为-1,所以它是从拦截器链条的第一个拦截器开始调用拦截器的。先++。
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.
//调用拦截器。注意:这个对象把自己作为参数。这就是为什么拦截器中又可以调用这个proceed()方法的原因。
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}

现在用一张图来解释上面的代码。

浅色小框表示连接点。深色大框表示拦截器(第一个深色框和最后一个深色框除外)。

箭头标表示程序的执行方向。我画的箭头的起始位置是非常严格的,比如后置通知的那个方框,箭头进来不是直接指向mi.proceed()那行代码的,意思是表示它之前可能还有代码。需要执行mi.proceed()那行代码之前的代码,然后才执行mi.proceed()这行,执行mi.proceed()的时候程序跳转到了连接点。在连接点中将取出下一个拦截器,调用它的invoke方法程序进入到下一个拦截器。当程序返回时,箭头并不是直接指向mi.proceed()这行代码的,说明这行代码已经执行完,现在执行mi.proceed()后面的代码。每个方法的底部都会有一个箭头指向上一个方框,箭头在方框的底部说明方法执行完毕并且return了。

根据上面的图,可以看出无论拦截器链中各个拦截器的顺序是什么样的,前置通知总是能够在调用目标方法之前执行,因为前置通知总是在mi.proceed()之前执行。而后置通知总是在目标方法之后执行,因为后置通知总是在mi.proceed()之后。但是返回通知和后置通知谁先执行呢???这个就跟它们在链条的顺序有关了。如上图,应该是返回通知先执行然后才到后置通知。

Joinpoint继承体系-笔记的更多相关文章

  1. Java基础知识强化之集合框架笔记02:集合的继承体系图解

    1. 集合的继承体系图解:

  2. 代码的坏味道(12)——平行继承体系(Parallel Inheritance Hierarchies)

    坏味道--平行继承体系(Parallel Inheritance Hierarchies) 平行继承体系(Parallel Inheritance Hierarchies) 其实是 霰弹式修改(Sho ...

  3. 从基层容器类看万变不离其宗的JAVA继承体系

    以容器类为例子,可以观一叶而知秋,看看以前的前辈们是如何处理各种面向对象思想下的继承体系的.读的源代码越多,就越要总结这个继承关系否则读的多也忘得快. 首先摆上一张图片: 看到这张图很多人就慌了,难道 ...

  4. 【09-23】js原型继承学习笔记

    js原型继承学习笔记 function funcA(){ this.a="prototype a"; } var b=new funcA(); b.a="object a ...

  5. Scala 深入浅出实战经典 第41讲:List继承体系实现内幕和方法操作源码揭秘

    Scala 深入浅出实战经典 第41讲:List继承体系实现内幕和方法操作源码揭秘 package com.parllay.scala.dataset /** * Created by richard ...

  6. 【转载】Javascript原型继承-学习笔记

    阮一峰这篇文章写的很好 http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javas ...

  7. 浅谈javascript继承体系

    最近做web项目,接触了jquery等框架,虽然使用方便,但是还是想学习下Javascript,今天分享下最近对js原型继承的理解,不足之处欢迎指正. 一.构造器的原型属性与原型对象 刚接触js时通常 ...

  8. ASP.NET MVC:如何提供 Controller 继承体系使用的 ModelBinder?

    背景 Mvc 提供了一种可扩展的模型绑定机制,具体来说就是:将客户端传递的参数按照一定的策略绑定到 action 的参数上,这带来的直接好处就是让 action 的参数支持强类型.一般来说我们有如下方 ...

  9. C++ 继承体系中的名称覆盖

    首先一个简单的样例: int x; int f() { double x; cin >> x; return x; } 在上述代码中.函数f的局部变量x掩盖了全局变量x.这得从 " ...

随机推荐

  1. jQuery源码分析-03构造jQuery对象-源码结构和核心函数

    3. 构造jQuery对象 3.1源码结构 先看看总体结构,再做分解: (function( window, undefined ) { var jQuery = (function() { // 构 ...

  2. C# 之String以及浅拷贝与深拷贝

     一.String到底是值类型还是引用类型 MSDN 中明确指出 String 是引用类型而不是值类型,但 String 表面上用起来却像是值类型,这又是什么原因呢? 首先从下面这个例子入手: //值 ...

  3. Java基础教程(9)--流程控制

    一.分支结构 1.if语句   if语句会与其后的第一条语句或代码块结合,且只有当判断条件为true时才执行语句或代码块.例如,自行车只有在运动的时候才可以减速,就像下面这样: void applyB ...

  4. ASP.NET MVC传递Model到视图的多种方式总结(二)__关于ViewBag、ViewData和TempData的实现机制与区别

    在ASP.NET MVC中,视图数据可以通过ViewBag.ViewData.TempData来访问,其中ViewBag 是动态类型(Dynamic),ViewData 是一个字典型的(Diction ...

  5. Docx4j将html转成word时,br标签为软回车的问题修改

    docx4j版本:3.0.1 修改jar包:docx4j-ImportXHTML maven配置为: 具体代码位置:\org\docx4j\convert\in\xhtml\XHTMLImporter ...

  6. python中GIL和线程与进程

    线程与全局解释器锁(GIL) 一.线程概论 1.何为线程 每个进程有一个地址空间,而且默认就有一个控制线程.如果把一个进程比喻为一个车间的工作过程那么线程就是车间里的一个一个流水线. 进程只是用来把资 ...

  7. visibilitychange:API详解

    利用页面可见性API搞个怪 继各大站点.博客在用console发招聘.玩游戏.埋彩蛋之后(知乎相关链接),小剧似乎又发现了一个好玩儿的东西,目测会火,利用页面可见性API做些小技俩. 页面可见性是什么 ...

  8. Python中操作HTTP请求的urllib模块详解

    urllib 是 Python 标准库中用于网络请求的库.该库有四个模块,分别是urllib.request,urllib.error,urllib.parse,urllib.robotparser. ...

  9. Django REST Framework应用

    一. 什么是RESTful REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移” REST从资源的角 ...

  10. 数学建模三剑客MSN

    前言 不管是不是巴萨的球迷,只要你喜欢足球,就一定听说过梅西(Messi).苏亚雷斯(Suarez)和内马尔(Neymar)这个MSN组合.在众多的数学建模辅助工具中,也有一个犀利无比的MSN组合,他 ...