是否可以在java中动态“添加”到类路径?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/402330/
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
Is it possible to "add" to classpath dynamically in java?
提问by
java -classpath ../classes;../jar;. parserTester
How can i get the functionality in the above command programmatically? Like, is it possible to run as:
如何以编程方式获得上述命令中的功能?比如,是否可以运行为:
java parserTester
and get the same result? I tried using URLClassLoader but it modifies the classpath and does not add to it.
并得到相同的结果?我尝试使用 URLClassLoader 但它修改了类路径并且没有添加到它。
Thanx!
谢谢!
Thanks for the response Milhous. But that is what i am trying to do.. How is it possible to get the jar into the classpath first? I tried using a custom classloader too :(
感谢米尔豪斯的回应。但这就是我想要做的..怎么可能先将 jar 放入类路径?我也尝试使用自定义类加载器:(
That works.. But sorry that i need to run it only as: java parserTester I would like to know if such a thing is possible???
那有效..但是很抱歉我只需要将它运行为:java parserTester 我想知道这样的事情是否可能???
It needs to be so bcoz i have parserTester.java and .class in a separate folder. I need to retain the file structure. The parserTester makes use of a jar in a separate jar folder.
它需要如此 bcoz 我有 parserTester.java 和 .class 在一个单独的文件夹中。我需要保留文件结构。parserTester 使用单独的 jar 文件夹中的 jar。
回答by Milhous
You could implement your own class loader, but that class/jar has to be in the classpath for it to be executed.
您可以实现自己的类加载器,但该类/jar 必须在类路径中才能执行。
try
尝试
java -cp *.jar:. myClass
or
或者
export CLASSPATH=./lib/tool.jar:.
java myClass
or
或者
java -jar file.jar
回答by OscarRyz
Did I understand right?! The only reason you have it that you want to launch your class without specifying the classpath and load it at runtime? ...
我理解对了吗?!想要在不指定类路径的情况下启动类并在运行时加载它的唯一原因是什么?...
java parserTester
java解析器测试器
instead of
代替
java -classpath ../classes;../jar;. parserTester
java -classpath ../classes;../jar;. 解析器测试器
Probably I didn't get your reason. But if "that's" what you want you can do the following ( although it does not make much sense to me )
可能我没有得到你的理由。但是,如果“那是”您想要的,则可以执行以下操作(尽管对我来说没有多大意义)
- Launch the class
- From the main method lauch another class an programatically set the classpath there.
- End of history.
- 开课
- 从 main 方法启动另一个类,并以编程方式在那里设置类路径。
- 历史的终结。
Something like the following "java -pseudo code "
类似于下面的“java -伪代码”
public static void main( String [] args ) {
String classpath = "classes;../jar";
Runtime.getRuntime().execute("java + classpath + " parserTester ");
}
Please tell me if I get it right. If you want to do something else I would gladly help.
请告诉我是否正确。如果您想做其他事情,我很乐意提供帮助。
回答by Jim Barrows
I have to agree with the other two posters, it sounds like you're overcomplicating a test class. It's not that unusual to have the .java and .class files in separate folders, while depending on jar files in yet a third, without programmatically changing the classpath. If you're doing it because you don't want to have to type the classpath on the command line everytime, I would suggest a shell script or batch file. Better yet, an IDE. The question I really have is why are you doing trying to manage the classpath in code?
我必须同意其他两张海报,这听起来像是让测试课程过于复杂。将 .java 和 .class 文件放在不同的文件夹中,同时又依赖于三分之一的 jar 文件,而不以编程方式更改类路径,这并不少见。如果您这样做是因为您不想每次都在命令行上键入类路径,我建议您使用 shell 脚本或批处理文件。更好的是,IDE。我真正的问题是你为什么要尝试在代码中管理类路径?
回答by raffimd
You can write a batch file or shell script file to export the classpath and run the java program. In Windows,
您可以编写一个批处理文件或shell脚本文件来导出类路径并运行java程序。在 Windows 中,
set classpath=%classpath%;../classes;../jars/* java ParserTester
set classpath=%classpath%;../classes;../jars/* java ParserTester
In Unix, export classpath=%classpath%:../classes:../jars/* java ParserTester
在Unix中,export classpath=%classpath%:../classes:../jars/* java ParserTester
If you name the file name as parser.bat or parser.sh, you can just run that by calling parser in respective OS.
如果您将文件名命名为 parser.bat 或 parser.sh,则可以通过在相应的操作系统中调用 parser 来运行它。
From java 1.6, you can include all the jars in a directory into the classpath just by saying /*
从 java 1.6 开始,您只需说 /* 就可以将目录中的所有 jar 包含到类路径中
If you are trying to generate a java file dynamically, compile and add into the classpath, set the directory into which the class file gets generated in the classpath beforehand. It should load the class. If you are modifying the already generated java class, basically recompiling after modification and if you want to load the new class, you need to use your custom class loader to avoid the caching of the class.
如果尝试动态生成java文件,编译并添加到类路径中,事先在类路径中设置生成类文件的目录。它应该加载类。如果是修改已经生成的java类,基本上是修改后重新编译,如果要加载新的类,就需要使用自定义的类加载器来避免类的缓存。
回答by Lawrence Dol
You can use a java.net.URLClassLoader to load classes with any program defined list of URL's you wish:
您可以使用 java.net.URLClassLoader 加载具有您希望的任何程序定义的 URL 列表的类:
public class URLClassLoader extends SecureClassLoader
This class loader is used to load classes and resources from a search path of URLs referring to both JAR files and directories. Any URL that ends with a '/' is assumed to refer to a directory. Otherwise, the URL is assumed to refer to a JAR file which will be opened as needed.
The AccessControlContext of the thread that created the instance of URLClassLoader will be used when subsequently loading classes and resources.
The classes that are loaded are by default granted permission only to access the URLs specified when the URLClassLoader was created.
Since: 1.2
公共类 URLClassLoader 扩展 SecureClassLoader
这个类加载器用于从引用 JAR 文件和目录的 URL 的搜索路径加载类和资源。任何以“/”结尾的 URL 都被假定为指向一个目录。否则,该 URL 被假定为引用将根据需要打开的 JAR 文件。
创建 URLClassLoader 实例的线程的 AccessControlContext 将在随后加载类和资源时使用。
默认情况下,加载的类仅被授予访问创建 URLClassLoader 时指定的 URL 的权限。
自:1.2
And a little fancy footwork can extend it to support using wildcarded pathnames to pick up entire directories of JARs (this code has some references to utility methods, but their implementation should be obvious in the context):
并且一些花哨的步法可以扩展它以支持使用通配符路径名来获取 JAR 的整个目录(此代码有一些对实用程序方法的引用,但它们的实现在上下文中应该是显而易见的):
/**
* Add classPath to this loader's classpath.
* <p>
* The classpath may contain elements that include a generic file base name. A generic basename
* is a filename without the extension that may begin and/or end with an asterisk. Use of the
* asterisk denotes a partial match. Any files with an extension of ".jar" whose base name match
* the specified basename will be added to this class loaders classpath. The case of the filename is ignored.
* For example "/somedir/*abc" means all files in somedir that end with "abc.jar", "/somedir/abc*"
* means all files that start with "abc" and end with ".jar", and "/somedir/*abc*" means all files
* that contain "abc" and end with ".jar".
*
*/
public void addClassPath(String cp) {
String seps=File.pathSeparator; // separators
if(!File.pathSeparator.equals(";")) { seps+=";"; } // want to accept both system separator and ';'
for(StringTokenizer st=new StringTokenizer(cp,seps,false); st.hasMoreTokens(); ) {
String pe=st.nextToken();
File fe;
String bn=null;
if(pe.length()==0) { continue; }
fe=new File(pe);
if(fe.getName().indexOf('*')!=-1) {
bn=fe.getName();
fe=fe.getParentFile();
}
if(!fe.isAbsolute() && pe.charAt(0)!='/' && pe.charAt(0)!='\') { fe=new File(rootPath,fe.getPath()); }
try { fe=fe.getCanonicalFile(); }
catch(IOException thr) {
log.diagln("Skipping non-existent classpath element '"+fe+"' ("+thr+").");
continue;
}
if(!GenUtil.isBlank(bn)) {
fe=new File(fe,bn);
}
if(classPathElements.contains(fe.getPath())) {
log.diagln("Skipping duplicate classpath element '"+fe+"'.");
continue;
}
else {
classPathElements.add(fe.getPath());
}
if(!GenUtil.isBlank(bn)) {
addJars(fe.getParentFile(),bn);
}
else if(!fe.exists()) { // s/never be due getCanonicalFile() above
log.diagln("Could not find classpath element '"+fe+"'");
}
else if(fe.isDirectory()) {
addURL(createUrl(fe));
}
else if(fe.getName().toLowerCase().endsWith(".zip") || fe.getName().toLowerCase().endsWith(".jar")) {
addURL(createUrl(fe));
}
else {
log.diagln("ClassPath element '"+fe+"' is not an existing directory and is not a file ending with '.zip' or '.jar'");
}
}
log.diagln("Class loader is using classpath: \""+classPath+"\".");
}
/**
* Adds a set of JAR files using a generic base name to this loader's classpath. See @link:addClassPath(String) for
* details of the generic base name.
*/
public void addJars(File dir, String nam) {
String[] jars; // matching jar files
if(nam.endsWith(".jar")) { nam=nam.substring(0,(nam.length()-4)); }
if(!dir.exists()) {
log.diagln("Could not find directory for Class Path element '"+dir+File.separator+nam+".jar'");
return;
}
if(!dir.canRead()) {
log.error("Could not read directory for Class Path element '"+dir+File.separator+nam+".jar'");
return;
}
FileSelector fs=new FileSelector(true).add("BaseName","EG",nam,true).add("Name","EW",".jar",true);
if((jars=dir.list(fs))==null) {
log.error("Error accessing directory for Class Path element '"+dir+File.separator+nam+".jar'");
}
else if(jars.length==0) {
log.diagln("No JAR files match specification '"+new File(dir,nam)+".jar'");
}
else {
log.diagln("Adding files matching specification '"+dir+File.separator+nam+".jar'");
Arrays.sort(jars,String.CASE_INSENSITIVE_ORDER);
for(int xa=0; xa<jars.length; xa++) { addURL(createUrl(new File(dir,jars[xa]))); }
}
}
private URL createUrl(File fe) {
try {
URL url=fe.toURI().toURL();
log.diagln("Added URL: '"+url.toString()+"'");
if(classPath.length()>0) { classPath+=File.pathSeparator; }
this.classPath+=fe.getPath();
return url;
}
catch(MalformedURLException thr) {
log.diagln("Classpath element '"+fe+"' could not be used to create a valid file system URL");
return null;
}
}
回答by Alvarock
Excellent good post, in my case I did this to work well (note: Windows specific):
优秀的好帖子,就我而言,我这样做是为了很好地工作(注意:Windows 特定):
set classpath=%classpath%;../lib/*
java -cp %classpath% com.test.MyClass
回答by user804965
I think what you want is an "Execution Wrapper" or a platform specific "Launcher"... typically this component is used to detect your OS and architecture and dependencies and then makes adjustments before launching your application. It is an old school design pattern (talking 80's and earlier) but is still used a lot today. The idea is that you program can be system and environment agnostic and the launcher will make preparations and tell the software everything it needs to know. Many modern open source programs do this with Shell scripts and Batch Files, etc... Apache Tomcat for example. You could just as easily make the wrapper in java an have it launch the software with a command line exec (be sure to add " &" to the end of you exec command in *NIX so your wrapper can exit leaving only your software running... also lets you close the shell window without killing the process)
我认为您想要的是“执行包装器”或特定于平台的“启动器”……通常此组件用于检测您的操作系统、架构和依赖项,然后在启动应用程序之前进行调整。这是一个老派的设计模式(谈论 80 年代及更早),但今天仍然被大量使用。这个想法是你的程序可以与系统和环境无关,启动器将做好准备并告诉软件它需要知道的一切。许多现代开源程序使用 Shell 脚本和批处理文件等来做到这一点......例如 Apache Tomcat。您可以轻松地在 java 中制作包装器,让它使用命令行 exec 启动软件(确保在 *NIX 中的 exec 命令末尾添加“&”,以便您的包装器可以退出,只留下您的软件运行。 . . 还可以让您在不终止进程的情况下关闭 shell 窗口)