java - Use object created by Classloader without interface call or reflect invoke? -
i'm using java thing same c++ dynamic library usage.
i didn't find way directly use same class object without reflect invoke style code.
this dynamic library code, make jar.
package com.demo; public class logic { public string dowork() { system.out.println("hello dll"); return "dll"; } } in main application, can create instance urlclassloader, invoke reflect fine:
public class main { public static void main(string[] args) throws malformedurlexception, classnotfoundexception, illegalaccessexception, instantiationexception, nosuchmethodexception, invocationtargetexception { file file = new file("c:\\plugin.jar"); url url = file.touri().tourl(); url[] urls = {url}; classloader parentloader = thread.currentthread().getcontextclassloader(); classloader loader = new urlclassloader(urls, parentloader); thread.currentthread().setcontextclassloader(loader); class<?> clazz = loader.loadclass("com.demo.logic"); system.out.println("new instance!!"); object logic = clazz.newinstance(); method method = logic.getclass().getmethod("dowork"); method.invoke(logic); } output:
new instance!! hello dll but when change code without using reflect invoke:
public class main { public static void main(string[] args) throws malformedurlexception, classnotfoundexception, illegalaccessexception, instantiationexception, nosuchmethodexception, invocationtargetexception { file file = new file("c:\\plugin.jar"); url url = file.touri().tourl(); url[] urls = {url}; classloader parentloader = thread.currentthread().getcontextclassloader(); classloader loader = new urlclassloader(urls, parentloader); thread.currentthread().setcontextclassloader(loader); class<?> clazz = loader.loadclass("com.demo.logic"); logic logic = (logic)clazz.newinstance(); logic.dowork(); } } compile success(compile external modules), when run program, failed @ line logic logic = (logic)clazz.newinstance();
exception:
exception in thread "main" java.lang.noclassdeffounderror: com/demo/logic @ main.main(main.java:31) @ sun.reflect.nativemethodaccessorimpl.invoke0(native method) @ sun.reflect.nativemethodaccessorimpl.invoke(nativemethodaccessorimpl.java:57) @ sun.reflect.delegatingmethodaccessorimpl.invoke(delegatingmethodaccessorimpl.java:43) @ java.lang.reflect.method.invoke(method.java:606) @ com.intellij.rt.execution.application.appmain.main(appmain.java:140) caused by: java.lang.classnotfoundexception: com.demo.logic @ java.net.urlclassloader$1.run(urlclassloader.java:366) @ java.net.urlclassloader$1.run(urlclassloader.java:355) @ java.security.accesscontroller.doprivileged(native method) @ java.net.urlclassloader.findclass(urlclassloader.java:354) @ java.lang.classloader.loadclass(classloader.java:425) @ sun.misc.launcher$appclassloader.loadclass(launcher.java:308) @ java.lang.classloader.loadclass(classloader.java:358) ... 6 more is there way make work? without reflect/interface.(in c++ can achieve this, share same struct/class declare, make sure using same compiler compile 2 parts. imho java also)
additional explanation 1
i want change current classloader behavior make recognize dynamic loaded class, try simple , naive, can't find other direction:
classloader parentloader = thread.currentthread().getcontextclassloader(); classloader loader = new urlclassloader(urls, parentloader); thread.currentthread().setcontextclassloader(loader);
in order make work, have logically split classes 3 sets:
- your main class
- your plugin classes
- your plugin-dependent classes
when creating new class loader, have ensure classes #2 and #3 both loaded same class loader because urlclassloader delegation goes towards parent. means classes in jvm application class loader, loaded main class, cannot see class in new class loader. in order work c, have update classpath of main class, , not supported (it possible, not supported; i've read java 9 remove capability).
in practice, should split main class 2 pieces (#1 , #3), , use reflection load/invoke plugin-dependent class (one reflection call, , if plugin-dependent class implements runnable, use ((runnable)loadclass("plugindependent").newinstance()).run() reduce that). however, need ensure urlclassloader not delegate load of plugin-dependent class, example:
split application 3 discrete sets listed above (main.jar, plugin.jar, , main-plugin-dependent.jar), , list of them on urlclassloader.
change creation of urlclassloader specify explicit null parent not delegate jvm application class loader, , specify both plugin.jar and main jar.
write custom urlclassloader overrides loadclass ensure plugin-dependent classes loaded class loader rather being delegated jvm application class loader.
Comments
Post a Comment