使用自定义 class 加载程序加载静态方法
Loading a static method using custom class loader
我有一个自定义 class 加载程序,如下所示
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class MyClassLoader extends ClassLoader
{
public String invoke(final String className, final String methodName, final String someString)
{
try {
final ClassLoader classLoader = getClass().getClassLoader();
final Class loadedClass = classLoader.loadClass(className);
final Constructor constructor = loadedClass.getConstructor();
final Object myClassObject = constructor.newInstance();
final Method method = loadedClass.getMethod(methodName, String.class);
final Object testStr = method.invoke(myClassObject, someString);
System.out.println(loadedClass.getClassLoader());
return (String) testStr;
}
catch (final ClassNotFoundException e) {
e.printStackTrace();
}
catch (final Exception e) {
e.printStackTrace();
}
return null;
}
}
和一个 class 名为 Bus
public class Bus
{
public static String connection(final String incoming)
{
return "Bus " + incoming;
}
}
和测试人员 class 来测试代码
public class Tester
{
public static void main(final String[] args) throws InterruptedException
{
for (int i = 0; i < 3; i++) {
final MyClassLoader mcl = new MyClassLoader();
final String s = mcl.invoke("Bus", "connection", "awesome");
System.out.println("Tester: " + s);
Thread.sleep(300);
}
}
}
问题:为什么MyClassLoader里面的sysout总是打印同一个对象(a.k.a class loader)?我做错了什么?
我想要实现的是对于测试器 class 中的每次迭代,我希望将总线 class 加载到新的 class 加载器
你的自定义class加载器MyClassLoader
使用java.lang.ClassLoader
的loadClass(String className)
方法。ClassLoader
的loadClass
方法的工作原理授权、唯一性和可见性。首先,您的自定义 MyClassLoader
检查父 classLoader 是否已经加载了 class 或 not.Since 你还没有定义 MyClassLoader 的父 classLoader,它需要 SystemClassLoader
使用 java.lang.ClassLoader
的 getSystemClassLoader()。 所以实际上,你 classes由 SystemClassLoader 加载,所有对象都由单个类加载器加载。根据唯一性原则,每个 class 只加载一次,由其父级加载或由其自身加载。
http://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html#ClassLoader()
您的 MyClassLoader 目前如何工作:-
public class MyClassLoader extends ClassLoader
{
//supplied by compiler
public MyClassLoader(){
super();
}
}
java.lang.ClassLoader
的默认构造函数使用 SystemClassLoader
加载 classes
protected ClassLoader() {
this.parent = getSystemClassLoader();
initialized = true;
}
loadClass
java.lang.ClassLoader 的方法:-
308 protected synchronized Class<?> More ...loadClass(String name, boolean resolve)
309 throws ClassNotFoundException
310 {
311 // First, check if the class has already been loaded
312 Class c = findLoadedClass(name);
313 if (c == null) {
314 try {
315 if (parent != null) {
316 c = parent.loadClass(name, false);
您需要实现自己的 class 加载程序,而不是只使用系统 class 加载程序。这是一种相当简单的方法,仅当 class 文件位于预期目录中时才有效。
public class MyClassLoader extends ClassLoader
{
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
try {
byte b[] = Files.readAllBytes(Paths.get("target/classes/"+name+".class"));
ByteBuffer bb = ByteBuffer.wrap(b);
return super.defineClass(name, bb,null);
} catch (IOException ex) {
return super.loadClass(name);
}
}
public String invoke(final String className, final String methodName, final String someString)
{
try {
final ClassLoader classLoader = this;
...
我有一个自定义 class 加载程序,如下所示
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class MyClassLoader extends ClassLoader
{
public String invoke(final String className, final String methodName, final String someString)
{
try {
final ClassLoader classLoader = getClass().getClassLoader();
final Class loadedClass = classLoader.loadClass(className);
final Constructor constructor = loadedClass.getConstructor();
final Object myClassObject = constructor.newInstance();
final Method method = loadedClass.getMethod(methodName, String.class);
final Object testStr = method.invoke(myClassObject, someString);
System.out.println(loadedClass.getClassLoader());
return (String) testStr;
}
catch (final ClassNotFoundException e) {
e.printStackTrace();
}
catch (final Exception e) {
e.printStackTrace();
}
return null;
}
}
和一个 class 名为 Bus
public class Bus
{
public static String connection(final String incoming)
{
return "Bus " + incoming;
}
}
和测试人员 class 来测试代码
public class Tester
{
public static void main(final String[] args) throws InterruptedException
{
for (int i = 0; i < 3; i++) {
final MyClassLoader mcl = new MyClassLoader();
final String s = mcl.invoke("Bus", "connection", "awesome");
System.out.println("Tester: " + s);
Thread.sleep(300);
}
}
}
问题:为什么MyClassLoader里面的sysout总是打印同一个对象(a.k.a class loader)?我做错了什么?
我想要实现的是对于测试器 class 中的每次迭代,我希望将总线 class 加载到新的 class 加载器
你的自定义class加载器MyClassLoader
使用java.lang.ClassLoader
的loadClass(String className)
方法。ClassLoader
的loadClass
方法的工作原理授权、唯一性和可见性。首先,您的自定义 MyClassLoader
检查父 classLoader 是否已经加载了 class 或 not.Since 你还没有定义 MyClassLoader 的父 classLoader,它需要 SystemClassLoader
使用 java.lang.ClassLoader
的 getSystemClassLoader()。 所以实际上,你 classes由 SystemClassLoader 加载,所有对象都由单个类加载器加载。根据唯一性原则,每个 class 只加载一次,由其父级加载或由其自身加载。
http://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html#ClassLoader()
您的 MyClassLoader 目前如何工作:-
public class MyClassLoader extends ClassLoader
{
//supplied by compiler
public MyClassLoader(){
super();
}
}
java.lang.ClassLoader
的默认构造函数使用 SystemClassLoader
加载 classes
protected ClassLoader() {
this.parent = getSystemClassLoader();
initialized = true;
}
loadClass
java.lang.ClassLoader 的方法:-
308 protected synchronized Class<?> More ...loadClass(String name, boolean resolve)
309 throws ClassNotFoundException
310 {
311 // First, check if the class has already been loaded
312 Class c = findLoadedClass(name);
313 if (c == null) {
314 try {
315 if (parent != null) {
316 c = parent.loadClass(name, false);
您需要实现自己的 class 加载程序,而不是只使用系统 class 加载程序。这是一种相当简单的方法,仅当 class 文件位于预期目录中时才有效。
public class MyClassLoader extends ClassLoader
{
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
try {
byte b[] = Files.readAllBytes(Paths.get("target/classes/"+name+".class"));
ByteBuffer bb = ByteBuffer.wrap(b);
return super.defineClass(name, bb,null);
} catch (IOException ex) {
return super.loadClass(name);
}
}
public String invoke(final String className, final String methodName, final String someString)
{
try {
final ClassLoader classLoader = this;
...