如何从数据库加载 java 类?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5329685/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I load java class from database?
提问by Koerr
With the following source code:
使用以下源代码:
package util.abc;
public class Test{
public String out(){
return "Hello World!";
}
}
I can use:
我可以用:
Class c = Class.forName("util.abc.Test");
to instantiate this Class, but I must put this source file(Test.java
) in the classpath /util/abc/
实例化这个类,但我必须把这个源文件(Test.java
)放在类路径中/util/abc/
I want to dynamically load this class from the database (store the source code as string
or binary
)
我想从数据库动态加载这个类(将源代码存储为string
or binary
)
Is this possible ?
这可能吗 ?
回答by Pa?lo Ebermann
Assuming you already compiled the class, you can create a DatabaseClassLoader
, which loads the class from a database.
假设您已经编译了该类,您可以创建一个DatabaseClassLoader
从数据库加载该类的 。
public class DatabaseClassLoader extends ClassLoader {
public DatabaseClassLoader(ClassLoader parent, ... /* connection to database */ ) {
super(parent);
// store the connection
}
public Class findClass(String name) {
byte[] data = loadDataFromDatabase(name);
return defineClass(name, data, 0, data.length);
}
private byte[] loadDataFromDatabase(String name) {
// this is your job.
}
}
If the database only contains the source code, you'll have to compile it first - look into the Java compiler API for how to do this without any files.
如果数据库只包含源代码,您必须先编译它 - 查看 Java 编译器 API 了解如何在没有任何文件的情况下执行此操作。
Pay attention, the class loaded this way will stay alive as long as the classloader is alive, so you'll need a new class loader to be able to reload the class in case of changes.
请注意,只要类加载器处于活动状态,以这种方式加载的类就会保持活动状态,因此您需要一个新的类加载器,以便在发生更改时能够重新加载该类。
Also, if you want to interact with the class by other ways than reflection, you would better let it implement some interface (which itself is in your class path), and let the application class loader be the parent of your database class loader.
此外,如果您想通过反射以外的其他方式与类进行交互,您最好让它实现一些接口(它本身在您的类路径中),并让应用程序类加载器成为数据库类加载器的父类。
Ah, and how to load:
啊,以及如何加载:
Class<?> c = Class.forName("util.abc.Test", myClassLoader);
or directly
或直接
Class<?> c = myClassLoader.loadClass("util.abc.Test");
Here is a method which creates objects of your interface (of any interface, in fact):
这是一个创建界面对象(实际上是任何界面)的方法:
public <X> X getImplementingObject(Class<X> interfaceClass, String className)
throws ClassNotFoundException, IllegalAccessException, InstantiationException
{
ClassLoader loader = new DatabaseClassLoader(interfaceClass.getClassLoader(), ...);
Class<?> cl = loader.loadClass(className);
Class<? extends X> c = cl.asSubclass(interfaceClass);
return c.newInstance();
}
(It needs the class to have a no-argument constructor which does not throw any exceptions, of course (if it does, you'll get this exception thrown, too).
(当然,它需要该类有一个不抛出任何异常的无参数构造函数(如果是这样,你也会抛出这个异常)。
This creates a new ClassLoader for every such class, so they can only cooperate with each other by means of the interface (or reflection).
这会为每个这样的类创建一个新的 ClassLoader,因此它们只能通过接口(或反射)的方式相互协作。
For on-the-fly compiling you should look at the Java Compiler API, as mentioned in the answer from dcn. But I think it would be better to do the compiling on the side which puts the classes into the database than the side who pulls them out.
对于即时编译,您应该查看 Java Compiler API,如dcn的答案中所述。但我认为最好在将类放入数据库的一侧进行编译,而不是在将它们取出的一侧进行编译。
回答by dcn
If you want to store the source code in you DB, you can use the Java 6 Compiler API to compile it at runtime. See herefor an example.
如果要将源代码存储在数据库中,可以使用 Java 6 Compiler API 在运行时对其进行编译。有关示例,请参见此处。
In order to load classes at runtime, you can either use an URLClassLoader if you can specify the location of the bytecode with a URL, or use ClassLoader.defineClassand supply the bytecode as an array of bytes.
为了在运行时加载类,如果可以使用 URL 指定字节码的位置,则可以使用 URLClassLoader,或者使用ClassLoader.defineClass并将字节码作为字节数组提供。
Either way you should pay attention, that in order to use your dynamically loaded class, it should implement an interface that is known at compile time.
无论哪种方式,您都应该注意,为了使用动态加载的类,它应该实现一个在编译时已知的接口。