在java spring中,是否可以动态将一个新的class加载到beanFactory中?是否可以将class类以字节流的方式存到redis中,再由类加载器重新加载到java运行实例中?
目前项目中有一个需求,需要可以动态地加载类到spring的beanFactory中或者说applicationContext里面,这个类是可以由开发人员动态上传到生产环境中,而无需重新启动生产环境。请问是否可以做到呢?还有一个问题,是否可以将class文件以字节的方式暂存在redis中间件上,需要用这个class时,动态地加载它?
PHPz2017-04-18 10:28:24
JDK1.5 以降には、この機能を実装するための既製の API java.lang.instrument.Instrumentation があります。
リーリー上記のインターフェースは既存の class
を再定義できます。
以下のように使用します。 class
。
像下面的方式使用。
java.lang.instrument.Instrumentation.redefineClasses(ClassDefinition... definitions)
获取Instrumentation
对象的方法:
private void redefineScripts(File dir) {
File[] files = dir.listFiles();
for (File f : files) {
if (f.isDirectory()) {
redefineScripts(f);
} else if (f.getName().endsWith(".class")) {
String name = getScriptCanonicalName(f);
String path = name.replaceAll("\.", "/");
File target = new File(targetDir, path + ".class");
try {
InputStream in = new FileInputStream(target);
byte[] buf = StreamUtils.copyToByteArray(in);
ClassDefinition cdef = new ClassDefinition(scriptClassLoader.loadClass(name), buf);
instrumentation.redefineClasses(cdef);
} catch (Exception ex) {
throw new ScriptException(ex);
}
}
}
}
agent.jar
打包时需要指定Agent-Class
,Can-Redefine-Classes
开启类重写义功能。
private void loadAgent() {
try {
String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
VirtualMachine vm = VirtualMachine.attach(pid);
vm.loadAgent("<jar file>", OBJECT_NAME.toString());
vm.detach();
} catch (Exception ex) {
throw new RuntimeException(
"无法加载代理JAR文件["
+ Typhons.getProperty(Constants.AGENT_JAR_PATH) + "]", ex);
}
}
Agent.java
实现
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestEntries>
<Agent-Class>org.skfiy.typhon.agent.Agent</Agent-Class>
<Can-Redefine-Classes>true</Can-Redefine-Classes>
</manifestEntries>
</archive>
</configuration>
</plugin>
这里我是通过JMX
将Instrumentation
对象注入过去的,当时为什么要这样来做呢。
是因为vm.loadAgent();
运行的环境是一个全新的,我无法使用静态方法来设置属性,虽然类相同但是加载该个类的ClassLoader
却不一致。后面我尝试出可以使用JMX
的方式调用。
好了,只要拿到Instrumentation
リーリー
Instrumentation
オブジェクトを取得するメソッド: 🎜
リーリー
🎜agent.jar
はパッケージ化するときに Agent-Class
を指定する必要があり、Can-Redefine-Classes
はクラス書き換え機能をオンにします。 🎜
リーリー
🎜Agent.java
実装🎜
リーリー
🎜ここでは、JMX
を介して Instrumentation
オブジェクトを挿入しました。なぜこのようにしたのですか? vm.loadAgent();
の実行環境がまったく新しいため、クラスは同じですが、静的メソッドを使用してプロパティを設定することができません。そのクラスの code> がロードされています。 ClassLoader が矛盾しています。 後で、JMX
を使用して呼び出してみました。 🎜
🎜Instrumentation
オブジェクトを取得する限り、以前はできなかったことは何でもできるようになります。 🎜PHP中文网2017-04-18 10:28:24
ApplicationContext を通じて AutowireCapableBeanFactory を取得してから、createBean() または autowire() メソッドを呼び出してそれを注入してみます