类加载器特技:OSGi代码生成
2010-03-01 00:00:00 来源:WEB开发网增强是按需生成的
- 我们永远不会把一个增强类生成两次。我们继承的loadClass()方法首先会调用findLoadedClass(),如果失败会调用 parent.loadClass(),只有失败的时候它才会调用 findClass()。由于我们为名称用了一个严格的协议,保证findLoadedClass()在第二次请求相同类的增强类时候不会失败。这与桥接类加载器缓存相结合,我们得到了一个非常有效的方案,我们不会桥接同样的bundle空间两次,或者生产冗余的增强类。
这里我们必须强调通过反射调用defineClass()的选项。cglib使用这种方法。当我们希望用户给我们传递一个可用的类加载器时这是一种可行的方案。通过使用反射我们避免了在类加载器之上创建另一个类加载器的需要,只要调用它的defineClass()方法即可。
类空间一致性
到了最后,我们所做的是使用OSGi的模块层合并两个不同的、未关联的类空间。我们还引入了在这些空间中一种搜索顺序,其与邪恶的Java类路径搜索顺序相似。实际上,我们破坏了OSGi容器的类空间一致性。这里是糟糕的事情发生的一个场景:
框架使用包com.acme.devices,需要的是1.0版本。
应用使用包com.acme.devices,需要的是2.0版本。
类A直接饮用com.acme.devices.SinisterDevice。
类A$Enhanced在他自己的实现中使用了com.acme.devices.SinisterDevice。
因为我们搜索应用空间,首先A$Enhanced会被链接到com.acme.devices.SinisterDevice 2.0版,而他的内部代码是基于com.acme.devices.SinisterDevice 1.0编译的。
结果应用将会看到诡异的LinkageErrors或者ClassCastExceptions。不用说,这是个问题。
唉,自动处理这个问题的方式还不存在。我们必须简单的确保增强类的内部代码直接引用的是“非常私有的”类实现,不会被其他类使用。我们甚至可以为任何我们可能希望使用的外部API定义私有的适配器,然后在增强类代码中引用这些适配器。一旦我们有了一个良好定义的实现子空间,我们可以用这个知识来限制类泄露。现在我们仅仅向框架空间委托特殊的私有实现类的请求。这还会限定搜索顺序问题,使得应用优先搜索还是框架优先搜索对结果没有影响。让所有的事情都可控的一个好策略是有一个专有的包来包含所有增强类实现代码。那么桥接加载器就可以检查以那个包开头的类的名称并将它们委托给框架加载器做加载。最终,我们有时候可以对特定的单实例(singleton)包放宽这个隔离策略,例如org.osgi.framework - 我们可以安全的直接基于org.osgi.framework编译我们的增强类代码,因为在运行时所有在OSGi容器中的代码都会看到相同的org.osgi.framework - 这是由OSGi核心保证的。
更多精彩
赞助商链接