実行時に別のクラスが使用できるカスタムクラスを作成したいとしましょう。インスツルメントされたクラスの読み込みを避ける
package redefineconcept;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import java.lang.reflect.InvocationTargetException;
public class LoadingTest {
public static final String HelloWorldTag = "$HelloWorld";
public static void main(String[] args){
new LoadingTest().run();
}
private void run(){
InstanceUser u = new InstanceUser();
u.start();
Class <?> createdClass = createAndLoadFor(InstanceUser.class);
System.out.println(String.format("created new class %s", createdClass.getName()));
InstanceUser.canAccess = true;
try {
u.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private Class<?> createAndLoadFor(Class<?> clazz){
ByteBuddy byteBuddy = new ByteBuddy();
String newClassName = clazz.getName() + LoadingTest.HelloWorldTag;
DynamicType.Builder builder = byteBuddy
.subclass(Object.class)
.name(newClassName)
;
DynamicType.Unloaded<?> newType = builder.make();
return newType
.load(clazz.getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
.getLoaded();
}
}
class InstanceUser extends Thread{
public static volatile boolean canAccess = false;
Object instance;
@Override
public void run() {
while(!canAccess){}
String cn = this.getClass().getName() + LoadingTest.HelloWorldTag;
Class clazz;
try{
clazz = Class.forName(cn);
}catch(ClassNotFoundException e){
e.printStackTrace();
throw new RuntimeException();
}
try{
instance = clazz.getConstructor().newInstance();
}catch(NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e){
e.printStackTrace();
throw new RuntimeException();
}
}
}
これは機能します。しかし
、the ByteBuddy tutorialは、あなたが一度に一つの動的な型を作成しているので、マイナーな関連性があると循環依存関係に遭遇する可能性を検討するかもしれない
を示唆しています。ただし、タイプの動的作成によって、いわゆる補助タイプの作成がトリガーされる可能性があります。
これらのタイプは、作成中のダイナミックタイプへのアクセスを提供するために、自動的にByte Buddyによって作成されます。
このため、可能であれば、既存のClassLoaderを注入するのではなく、特定のClassLoaderを作成して動的に作成したクラスをロードすることをお勧めします。
私は、クラスローダーやByteBuddyについてはあまり知らないですが、このチュートリアルではクラスローダーが階層的に注文されているようです。
もしそうなら、新しいクラスローダをclazz.getClassLoader()
にチェーンすることは可能でしょうか?
まあ、私はClassLoadingStrategy.Default.WRAPPER
でもClassLoadingStrategy.Default.CHILD_FIRST
でもこのような運がなかった。
は、彼らが唯一のクエリ親通常、Javaクラスローダーが直接指定された名前のタイプをロードしようとする前に、親クラスローダを照会することを信じるように私を導い
内の両方の結果。created new class redefineconcept.InstanceUser$HelloWorld java.lang.ClassNotFoundException: redefineconcept.InstanceUser$HelloWorld
ClassLoader
のではなく、子どもたち
を意味します。 そうですか?
ClassLoadingStrategy.Default.INJECTION
をここで使用することは避けられますか?
とにかく 'Class.forName(cn)'を使用しているので、なぜクラスローダーの解決戦略を変更しようとしていますか?カスタムクラスローダーを使って、それを渡し、 'Class.forName(cn)'を 'customClassLoader.loadClass(cn)'に置き換えてください... – Holger