java - 将 cglib BeanCopier 与多个类加载器一起使用

标签 java javabeans cglib dynamic-class-loaders

我想在 Java 中将一个 bean 复制到另一个 bean。问题是它位于类加载杂耍框架内,并且两个类由不同的类加载器加载,这也与当前的类加载器不同。

需要以最有效的方式完成此操作,因此最好的方法是使用字节码生成解决方案(如 cglib BeanCopier),但不是基于反射的。

问题是 cglib BeanCopier 在这种情况下不起作用。显示它的最简单的代码是:

URL classesUrl = new File("/directory/with/class-files-for-Person").toURL();
Class<?> c1 = new URLClassLoader(new URL[] {classesUrl}).loadClass("Person");
Class<?> c2 = new URLClassLoader(new URL[] {classesUrl}).loadClass("Person");
Object o1 = c1.newInstance();
Object o2 = c2.newInstance();
BeanCopier copier = BeanCopier.create(o1.getClass(), o2.getClass(), false);
copier.copy(o1, o2, null);

它给出了异常(exception):

Exception in thread "main" java.lang.ClassCastException: Person cannot be cast to Person
at net.sf.cglib.empty.Object$$BeanCopierByCGLIB$$da60538e.copy(<generated>)
at Main.main(Main.java:22)

我正在寻找解决问题的方法。就我而言,这两个类是相同的,但加载了自定义类加载器。此外,这些属性仅包含 java.* 中的特权和类(因此它们由标准类加载器加载)。

最佳答案

这听起来像是 cglib 中存在一个错误,它只考虑类名而不查看类加载器。事实上,当您不使用使用较多的Enhancer时,cglib充满了错误,而BeanCopier则相当奇特。还有更多坏消息,cglib 的开发不是很活跃,所以修复这个 bug 最好的办法就是自己尝试。

您可以尝试的是将 Converter 添加为 copy 的第三个参数,并将第三个构造函数参数更改为 true 以激活此转换器。让 Converter 仅返回 value 参数。此解决方案的一个缺点是,每次复制值时,您的基元都会被装箱和取消装箱,这对性能来说非常糟糕。

不过,有个好消息。现代 JVM(例如 HotSpot)知道一个称为通货膨胀的概念。当多次应用特定反射(在当前 HotSpot JVM 上超过 15 次)时,就会应用膨胀。然后,JVM 创建与该反射调用相对应的字节代码,并用生成的字节代码替换它。这正是 BeanCopier 所做的,但有错误(显然)。因此,BeanCopier 已经是旧闻了。现代 JVM 足够聪明,可以自行应用这种优化。如果您想了解更多有关通货膨胀的信息,例如可以咨询HotSpot related javadoc .

为了进一步阅读,我发现 this article您可能会觉得有趣。

关于java - 将 cglib BeanCopier 与多个类加载器一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20816197/

相关文章:

Java - 创建随机排列而不使用临时列表

java - 使用 JSTL 将属性设置为默认值

c# - 有没有人有使用 cglib MulticastDelegate 来执行 C# 事件之类的示例代码?

java - Spring CGLIB 和 CGLIB 有什么区别?

java-bytecode-asm - 动态Java字节码操作框架比较

java - 无法使用新的 readObject()/writeObject() 方法反序列化对象

java - JGraphT 中的简单无向无标签图不起作用?什么是edgeClass参数?

java - 如何单击自动建议输入文本字段中的选项? Selenium 网络驱动程序

jsp - Tomcat 不适用于特定目录

java - 动态创建 POJO/bean 并使用 CGLib 设置值