Sunday, December 9, 2012

java.lang.reflect

说到 Java 自己的 reflection 一直不是很熟悉,这里稍微讨论一下几个相关的类。虽然标题写的是 java.lang.reflect 但是实际在 java.lang 里面也有不少息息相关的类。

那么第一个就是 ClassLoader 了,这算是 Java 的 dynamic linker 吧,说到底 Java 仍然不是一个动态的语言,比如 python 之流甚至可以动态(运行时)的为一个对象添加属性、方法,这在 Java 里面仍然是一个很困难的事情。JVM 获得一个 class 是通过 ClassLoader 做到的,这个东西本身的也很复杂(是一个层次结构,子类 load 之后需要在父类里面继续传递),有机会再仔细看看,但就系统自带的 Loader 拿到了这个 class 之后这个 class 相关的信息就可以用 Class 类来获取,当然 Class.forName 可以帮助我们从字符串找到需要的类的 Class 对象(这个区别就在于如果直接写 Foo.class 是编译时的,而字符串转换的话是运行时的)。

那么我们的故事大约就从 Class 开始,如何表述一个 Class 的方法和成员呢,java 提供了 Member 接口和 Method 这个类,可以 getName 获得成员名、方法名,后者还能 invoke,这样就相当于 C++ 里面通过 mem_fn 把方法拿出来做成的 functor 了。static 之类的修饰可以用 Modifier 来描述。构造函数单独用 Constructor 来表示。另外有点关系的就是 Package。这样我们可以通过 Class 对象拿到我们需要的不少信息了。

不过有时候我们希望存在一个对象,能够帮助我们 handle 任何可能的请求,那怎么办?比如我们常见 bean 他们都有 getter/setter,如果我们希望捕获任意的 Method,那是不是可以呢?在 Java 里面实现这个很难,但是如果你限制这些 Method 为某个/些 interface 里面声明的那些,我们其实还是可以通过 Proxy 来实现的,Proxy 通常用 factory method Proxy.newProxyInstance 来产生,传入的参数分别是 ClassLoader,一个 interface 的数组以及响应方法的 InvokationHandler 接口的实现。其实这个 Proxy 对象干的事情很简单,就是实现了所有的 interface,但实现的很简单,就是将对应的调用使用 Method 传递给 InvokationHandler,使用其 invoke 方法,这个方法传递 Proxy 对象本身,Method 与相关的参数列表 Object[] args,这样我们就能在这个 handler 里面决定如何 dispatch 这些方法(或者自己实现对应的请求)。

这一篇文章讲了一下如何能够 runtime 更新一个接口的实现,这类似 django/ruby on rails 那种的对开发还是很有帮助的。这里的窍门就是怎么样在一个类更新后产生新的 instance 替换掉原先的,那么借助 Proxy 就能将对应的调用传递给更新后的对象了。

这篇文章讲了一些 Proxy 在实际问题里面的三种用法
  • spring 里面实现了某种 interface 的 proxy,可以在将调用forward 之前设置好数据库连接一些相关的属性
  • testing 里面测试某个 interface 时通过一个 proxy 将其行为 wrap 起来,这样就可以在调用前后干点别的什么
  • AOP 里面实现在某个方法之前之后加入的 aspect

No comments:

Post a Comment