bmi*_*are 22 clojure classloader
我一直在阅读代码和文档,试图了解类重新加载在clojure中的工作原理.根据许多网站,如http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html,每当你加载一个类本质上你获得字节码(通过任何数据机制),转换将字节码转换为类Class的实例(通过defineClass),然后通过resolveClass解析(链接)该类.(defineClass是否隐式调用resolveClass?).任何给定的类加载器只允许链接一次类.如果它试图链接现有的类,它什么都不做.这会产生问题,因为您无法链接新实例化的类,因此每次重新加载类时都必须创建类加载器的新实例.
回到clojure,我尝试检查加载类的路径.
在clojure中,您可以根据需要以多种方式定义新类:
匿名类:reify代理
命名类:deftype defrecord(在引擎盖下使用deftype)gen-class
最终,这些代码指向clojure/src/jvm/clojure/lang/DynamicClassLoader.java
其中DynamicClassLoader/defineClass使用super的defineClass创建一个实例,然后缓存该实例.当你想要检索类时,clojure加载调用forName调用类加载器和DynamicClassLoader/findClass,它首先在委托给超类之前查看缓存(这与大多数普通类加载器的工作方式相反,它们在哪里首先委托,而不是自己尝试.)混淆的重点如下:forName被记录为在返回之前链接类,但这意味着你不能从现有的DynamicClassLoader重新加载一个类,而是需要创建一个新的DynamicClassLoader但是我没有在代码中看到这一点.我理解代理和reify定义了匿名类,因此它们的名称不同,因此可以将其视为不同的类.但是,对于命名类,这会破坏.在真正的clojure代码中,您可以同时引用旧版本的类和对新版本类的引用,但尝试创建新类实例将是新版本.
请解释一下clojure如何在不创建DynamicClassLoader的新实例的情况下重新加载类,如果我能理解重新加载类的机制,我想将这个重新加载功能扩展到我可能使用javac创建的java .class文件.
注意:此问题涉及类RELOADING,而不仅仅是动态加载.重新加载意味着我已经实习了一个类,但想要实例化该实例的新更新版本.
我想重申一下,不清楚clojure如何能够重新加载deftype定义的类.调用deftype最终会调用clojure.lang.DynamicClassLoader/defineClass.再次执行此操作会导致再次调用defineClass,但手动执行此操作会导致链接错误.在这里发生了什么,允许clojure使用deftypes做到这一点?
Cho*_*ser 31
并非所有这些语言功能都使用相同的技术.
该proxy宏生成被完全继承的类和接口列表基于类的名称.此类中每个方法的实现委托给存储在对象实例中的Clojure fn.这允许Clojure在每次继承相同的接口列表时使用相同的代理类,无论宏的主体是否相同.没有实际的类重新加载.
因为reify,方法体直接编译到类中,因此技巧proxy使用不起作用.相反,在编译表单时会生成一个新类,因此如果更改表单的主体并重新加载它,则会得到一个全新的类(使用新生成的名称).所以再次,没有实际的类重新加载.
随着gen-class你生成的类指定一个名称,这样既不的技术用于proxy或者reify将工作.一个gen-class宏包含只有一种规格为一类,但没有方法体.生成的类有点像proxy,遵循方法体的Clojure函数.但是因为名称与规范相关联,不像proxy它不能改变a的主体gen-class并重新加载它,所以gen-class只有在提前编译(AOT编译)时才可用,并且在不重新启动JVM的情况下不允许重新加载.
这是真正的动态类重新加载的地方.我对JVM的内部并不是很熟悉,但是对调试器和REPL的一点工作清楚地表明:每次需要解析类名时,例如编译使用该类的代码时或者forName调用类类的方法,使用Clojure的DynamicClassLoader/findClass方法.如您所知,这会在DynamicClassLoader的缓存中查找类名,并且可以通过deftype再次运行将其设置为指向新类.
请注意您提到的关于重新加载的类是另一个类的教程中的警告,尽管名称相同,仍然适用于Clojure类:
(deftype T [a b]) ; define an original class named T
(def x (T. 1 2)) ; create an instance of the original class
(deftype T [a b]) ; load a new class by the same name
(cast T x) ; cast the old instance to the new class -- fails
; ClassCastException java.lang.Class.cast (Class.java:2990)
Run Code Online (Sandbox Code Playgroud)
Clojure程序中的每个顶级表单都会获得一个新的DynamicClassLoader,用于该表单中定义的任何新类.这不仅包括通过deftype和定义的类,defrecord还包括reify和fn.这意味着x上面的类加载器与新的不同T.注意@s 之后的数字是不同的 - 每个都有自己的类加载器:
(.getClassLoader (class x))
;=> #<DynamicClassLoader clojure.lang.DynamicClassLoader@337b4703>
(.getClassLoader (class (T. 3 4)))
;=> #<DynamicClassLoader clojure.lang.DynamicClassLoader@451c0d60>
Run Code Online (Sandbox Code Playgroud)
但是只要我们不定义新T类,新实例将具有相同类和相同的类加载器.注意@这里的数字与上面的第二个相同:
(.getClassLoader (class (T. 4 5)))
;=> #<DynamicClassLoader clojure.lang.DynamicClassLoader@451c0d60>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3333 次 |
| 最近记录: |