假设我有一个名为NameGenerator
的班级。我可以使用它来根据给定的逻辑生成名称。然后我用一个方法写一个TestNameGeneration
类,该方法要求用户写一封信并按照生成名称。现在我想更改NameGeneration
类中的逻辑并在不停止应用程序的情况下应用该特定更改。
我这样做是为了了解更多关于类加载器的信息,有人可以解释一下我必须学会做的关键概念或者网站的任何引用吗?
答案 0 :(得分:30)
这是一个有效的测试。每隔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并使用反射调用了第一个方法。但是所有Test1依赖项都将使用Test1类加载器进行隐式加载,即所有Test1应用程序都将由JVM加载到TestClassLoader中。
答案 1 :(得分:2)
有两种方式:
希望有所帮助
答案 2 :(得分:1)
这很简单,你将利用OOP的优势并使用界面,不需要管理类加载器 您可以使用setter注入实现:
创建一个名为NameGeneration的接口 例如,创建n实现NameGenerationImpl1,NameGenerationimpl2 在您的客户端类中定义一个变量:
NameGeneration nameGeneration ;
和二传手:
public void setNameGeneration(NameGeneration nameGeneration) {
this.nameGeneration = nameGeneration ;
}
nameGeneration将生成您想要的内容。
当您更改算法时,您可以通过以下方式更改实现:
setNameGeneration(new NameGenerationImpl1()) ;
或
setNameGeneration(new NameGenerationImpl2()) ;
答案 3 :(得分:0)
strategy pattern怎么样?它可能是您问题的更好解决方案,而不是使用类加载器。
答案 4 :(得分:0)
您可以编写自己的自定义类加载器。当包含类文件的类文件或资源/ jar发生更改时(检查时间戳),销毁先前的类加载器实例并创建一个新的类加载器实例,该实例又将加载新的类文件。
答案 5 :(得分:0)
如果您正在使用企业级应用程序,并且希望避免在每次更改类时都重新加载应用程序上下文,那么使用DCEVM和HotSwapAgent可以帮助您更好。 下面的命令会将DCEVM添加到您的JDK中,
java -jar DCEVM-8u181-installer.jar
您必须在VM参数下方添加到Run命令(或)配置中
-XXaltjvm = dcevm -javaagent:您的目录位置/hotswap-agent-1.3.0.jar .jar = autoHotswap = true
参考:https://dzone.com/articles/hot-swap-java-bytecode-on-runtime