如何在java中运行正在运行的应用程序中的类?

假设我有一个名为NameGenerator的类。 我可以使用它根据给定的逻辑生成名称。 然后我用一个方法编写一个TestNameGeneration类,该方法要求用户写一封信并按照生成名称。 现在我想更改NameGeneration类中的逻辑并应用该特定更改而不停止应用程序。

我这样做是为了更多地了解类加载器,有人可以解释一下我必须学习做的事情或网站任何参考的关键概念吗?

这是一个工作测试。 每隔5秒Test.main()从文件系统重新加载test.Test1.class并调用Test1.hello()

 package test; public class Test1 { public void hello() { System.out.println("Hello !"); } } public class Test { static class TestClassLoader extends ClassLoader { @Override public Class loadClass(String name) throws ClassNotFoundException { if (name.equals("test.Test1")) { try { InputStream is = Test.class.getClassLoader().getResourceAsStream("test/Test1.class"); byte[] buf = new byte[10000]; int len = is.read(buf); return defineClass(name, buf, 0, len); } catch (IOException e) { throw new ClassNotFoundException("", e); } } return getParent().loadClass(name); } } public static void main(String[] args) throws Exception { for (;;) { Class cls = new TestClassLoader().loadClass("test.Test1"); Object obj = cls.newInstance(); cls.getMethod("hello").invoke(obj); Thread.sleep(5000); } } } 

运行。 然后更改并重新编译Test1

 System.out.println("Hello !!!"); 

测试正在运行。 您将看到Test1.hello输出已更改

 ... Hello ! Hello ! Hello !!! Hello !!! 

这就是Tomcat重新加载webapps的方式。 它为每个webapp都有一个单独的ClassLoader,并在新的ClassLoader中加载新版本。 旧的GCed就像任何Java对象以及旧类一样。

请注意,我们使用TestClassLoader加载Test1并使用reflection调用其第一个方法。 但是所有Test1依赖项都将使用Test1类加载器进行隐式加载,即所有Test1应用程序都将由JVM加载到TestClassLoader中。

有两种方式:

  1. 要覆盖您正在使用的类加载器,首先使用现有的类加载器来引导应用程序,特别是对于需要动态更新的类,必须使用覆盖的类加载器。
  2. 使用OSGi框架。 根据应用程序的规模,OSGi框架可能不是一个好的选择,因为它要求您遵循它的编码约定。

希望能帮助到你

编写自己的类加载器:

我以此为基础取得了成功您还应该看看本教程。

这很简单,你将利用OOP的优势并使用界面,不需要管理类加载器你可以使用setter注入实现:

创建一个名为NameGeneration的接口创建n实现NameGenerationImpl1,例如NameGenerationimpl2在您的客户端类中定义一个变量:

 NameGeneration nameGeneration ; 

和二传手:

  public void setNameGeneration(NameGeneration nameGeneration) { this.nameGeneration = nameGeneration ; } 

nameGeneration将生成您想要的内容。

当您更改算法时,您可以通过以下方式更改实现:

 setNameGeneration(new NameGenerationImpl1()) ; 

要么

 setNameGeneration(new NameGenerationImpl2()) ; 

策略模式怎么样 ? 对于您的问题而言,它可能是更好的解决方案,而不是使用类加载器。

您可以编写自己的自定义类加载器。 当包含类文件的类文件或资源/ jar发生更改时(检查时间戳),销毁先前的类加载器实例并创建一个新的类加载器实例,该实例又将加载新的类文件。