8

我正在寻找一种 Java 解决方案,它允许我使用 AOP 在运行时已经运行的代码之上编织新代码。关键是不需要重启JVM。另外,我想在运行时删除编织,让旧代码以编织前的方式运行。

我在想 AspectJ 加载时间编织 + 运行时类加载/卸载会做到这一点。有人试过吗?有什么建议吗?谢谢你。

4

3 回答 3

12

有几点需要考虑:

  • 诚然,您可以在类加载期间执行 LTW ,但不能已加载类之后执行。
  • 没有类卸载这样的概念,因为要卸载一个类,它需要进行垃圾回收,并且不再存在对该类的引用。即使是后者,JVM 规范 AFAIK 也将其声明为可选的,是否以及何时卸载或 GC 应清除已加载的类。你永远不能依赖它。

话虽如此,您可以尝试诸如 OSGi 之类的概念,也可以编写自己的类加载器(或在 Internet 上找到许多现有的类加载器之一),将每个类或每个 JAR 加载到单独的类加载器实例中。这可能会变得任意复杂,所以也许您想考虑这种简单的方法,只要它在您的情况的技术范围内:

  • 将您的方面编译到您的代码中或使用 LTW,这并不重要。只需确保在实际使用类之前编织方面代码。编译时间显然绰绰有余,加载时间刚刚够快,但很好。
  • 对所有相关的建议使用if()切入点,并提供一种动态更改切入点使用的变量值的方法,以便能够动态地打开和关闭建议。性能开销通常很小,不用担心。在你说它太贵之前先试一试。

此解决方案满足您的条件,即它可以动态(停用)激活,并且在编织方面代码后无需重新启动 JVM。

于 2013-07-13T11:54:57.177 回答
9

方面

一个方面是您正在实现的横切功能。它是您正在模块化的应用程序的方面或区域。方面最常见(尽管很简单)的示例是日志记录。日志记录是整个应用程序所必需的。但是,由于应用程序倾向于根据功能分解为层,因此通过继承重用日志记录模块

没有意义。但是,您可以创建一个日志记录方面并使用 AOP 在整个应用程序中应用它。


编织

编织是将方面应用到目标对象以创建新的代理对象的过程。这些方面在指定的连接点处被编织到目标对象中。编织可以在目标类的生命周期中的几个点发生:

  • 编译时间:编译目标类时会编织方面。这需要一个特殊的编译器。
  • 类加载时间:当目标类加载到 JVM 中时,方面会被编织。这需要一个特殊的 ClassLoader,在将类引入应用程序之前增强目标类的字节码。
  • 运行时:方面是在应用程序执行期间的某个时间编织的。通常,AOP 容器将动态生成一个代理类,该代理类将在编织方面时委托给目标类。

在此处输入图像描述
在此处输入图像描述

(资源)

于 2014-09-11T05:46:48.200 回答
0

您可以实现一个 ASM 解决方案,允许在运行时在已经运行的代码之上编织新代码(无需停机)

  • ASM 可以重新转换已经加载的类它基本上读取文件上的类并重新转换内存中加载的类
  • 使用 ASM 进行操作 ( https://www.baeldung.com/java-asm )

您可以使用相同的解决方案在运行时移除编织物

  • 加载的类保留在可以重新加载的文件系统上。
于 2018-12-27T08:10:23.200 回答