Java ClassLoader:如何从另一个项目加载类

Java ClassLoader:如何从另一个项目加载类,java,class,Java,Class,我想使用ClassLoader从另一个项目访问一个类。如何指定该类的路径并获取该类文件 我希望能够通过代码做到这一点,因为我将通过我的应用程序加载许多不同的类文件,不同类的路径将不断变化 我使用的是CustomClassLoader,它正在加载类文件,但仅当它们在项目中而不是在另一个项目中时 import java.io.FileInputStream; import java.security.AccessControlContext; import java.security.AccessC

我想使用ClassLoader从另一个项目访问一个类。如何指定该类的路径并获取该类文件

我希望能够通过代码做到这一点,因为我将通过我的应用程序加载许多不同的类文件,不同类的路径将不断变化

我使用的是CustomClassLoader,它正在加载类文件,但仅当它们在项目中而不是在另一个项目中时

import java.io.FileInputStream;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;

public class CustomClassLoader extends ClassLoader {

String repoLocation = "C:/TempBINfolder/bin/";

public CustomClassLoader() {
}

public CustomClassLoader(ClassLoader parent) {
    super(parent);
}

@Override
protected Class<?> findClass(final String name)
        throws ClassNotFoundException {

    AccessControlContext acc = AccessController.getContext();

    try {
        return (Class) AccessController.doPrivileged(
                new PrivilegedExceptionAction() {

                    public Object run() throws ClassNotFoundException {

                        FileInputStream fi = null;
                        try {

                            String path = name.replace('.', '/');
                            fi = new FileInputStream(repoLocation + path
                                    + ".class");
                            ByteArrayOutputStream baos = new ByteArrayOutputStream();
                            byte[] buffer = new byte[8192]; // a big chunk
                            int read;
                            while ((read = fi.read(buffer)) > 0)
                                baos.write(buffer, 0, read);
                            byte[] classBytes= baos.toByteArray();

                            return defineClass(name, classBytes, 0,
                                    classBytes.length);
                        } catch (Exception e) {
                            throw new ClassNotFoundException(name);
                        }
                    }
                }, acc);
    } catch (java.security.PrivilegedActionException pae) {
        return super.findClass(name);
    }
}
}
如果我尝试执行
Class cls=Class.forName(stringClass.getPackage()+“+stringClass.getName())包为
null

编辑:以下内容对我有用

URL classUrl;
classUrl = new URL("file:///"+ccl.getRepoLocation());    //This is location of .class file
URL[] classUrls = {classUrl};
URLClassLoader ucl = new URLClassLoader(classUrls);
Class cls = ucl.loadClass(stringClass.getName());    // Current .class files name
使用a来完成这项工作。

该代码看起来不错(很久以前我自己也做过类似的事情)。虽然有一个小错误:

如果你这样做

byte[] classBytes = new byte[fi.available()];
fi.read(classBytes);
您只读取没有阻塞的可用字节数。是的,你没有阅读整个文件。事实上,read方法不能保证读取完整的字节缓冲区

试着做:

ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[8192]; // a big chunk
int read;
while ((read = fi.read(buffer)) > 0)
   baos.write(buffer, 0, read);
byte[] bytesClass = baos.toByteArray();
或者从Apache使用。这也是一种方便的方法

包定义

类加载器有一个
definePackage
方法。我敢打赌,对于您需要的每个新包,您都应该调用该方法。否则,ClassLoader无法定义包,只能从完整的类名开始定义,这似乎是不够的

因此,代码要做到这一点:

// being package the name of the package for the new class
// being definedPackages a Set<String> member of the classloader

if (!this.definedPackages.contains(package)) {
   definePackage(package,"","","","","","",null);
   this.definedPackages.add(package);
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[8192]; // a big chunk
int read;
while ((read = fi.read(buffer)) > 0)
   baos.write(buffer, 0, read);
byte[] bytesClass = baos.toByteArray();
//是新类的包的名称
//正在定义打包类加载器的集合成员
如果(!this.definedPackages.contains(包)){
定义包(包“,”,“,”,“,”,“,”,null);
此.definedPackages.add(包);
}
ByteArrayOutputStream bas=新的ByteArrayOutputStream();
字节[]缓冲区=新字节[8192];//一大块
int-read;
而((read=fi.read(buffer))>0)
写入(缓冲区,0,读取);
字节[]ByteClass=baos.toByteArray();

感谢上述代码对我的帮助

SUB:在两个不同的位置调用相同的类

我在classpath jar文件中有一个类,比如说Abc,我在本地目录中动态地生成同一个类Abc,并进行一些代码更改

我需要创建实例并使用本地目录中的Abc类, 下面是工作代码

类CustomClassLoader扩展了类加载器{

String repoLocation = "./";
//C:/TempBINfolder/bin/
 CustomClassLoader() {
}

 CustomClassLoader(ClassLoader parent) {
    super(parent);
}

@Override
protected Class<?> findClass(final String name)   throws ClassNotFoundException {

    AccessControlContext acc = AccessController.getContext();

    try {
        return (Class) AccessController.doPrivileged(
                new PrivilegedExceptionAction() {

                    public Object run() throws ClassNotFoundException {

                        FileInputStream fi = null;
                        try {

                            String path = name.replace('.', '/');
                            fi = new FileInputStream(repoLocation + path+ ".class");
                            ByteArrayOutputStream baos = new ByteArrayOutputStream();
                            byte[] buffer = new byte[8192]; // a big chunk
                            int read;
                            while ((read = fi.read(buffer)) > 0)
                                baos.write(buffer, 0, read);
                            byte[] classBytes= baos.toByteArray();

                            return defineClass(name, classBytes, 0,
                                    classBytes.length);
                        } catch (Exception e) {
                            throw new ClassNotFoundException(name);
                        }
                    }
                }, acc);
    } catch (java.security.PrivilegedActionException pae) {
        return super.findClass(name);
    }
}
}
谢谢,
Murwath

这是如何使用的?您没有提到这些项目是如何捆绑的,也没有提到为什么要首先使用自定义类加载器。典型的情况是至少对每个项目进行jar,然后将依赖项jar放在另一个jar的类路径上(在这种情况下,您应该能够使用
parent.getResourceAsStream(“…”
)获取它)。一点也不。但是,问题不是加载类,而是正确地检索对应的包?(我误解了)是的,我可以得到这个类,但这只是为了得到这个类所在的包才是问题!好吧,在我的帖子中添加了definePackage…似乎是相关的:)但是我在我的CustomClassLoader(上面)中调用它,所以应该返回类路径,是吗?你必须调用definePackage(至少如果你以前没有定义这个包的话)然后调用defineClass。例如:
findClass(“a.b.C”)
被调用。然后调用
definecackage(“a.b”),然后调用
defineClass(…)
。因此,返回的类对象将附加到与刚才进行的definePackage调用相对应的新包对象。请记住,不要为同一个包调用definePackage两次。
String repoLocation = "./";
//C:/TempBINfolder/bin/
 CustomClassLoader() {
}

 CustomClassLoader(ClassLoader parent) {
    super(parent);
}

@Override
protected Class<?> findClass(final String name)   throws ClassNotFoundException {

    AccessControlContext acc = AccessController.getContext();

    try {
        return (Class) AccessController.doPrivileged(
                new PrivilegedExceptionAction() {

                    public Object run() throws ClassNotFoundException {

                        FileInputStream fi = null;
                        try {

                            String path = name.replace('.', '/');
                            fi = new FileInputStream(repoLocation + path+ ".class");
                            ByteArrayOutputStream baos = new ByteArrayOutputStream();
                            byte[] buffer = new byte[8192]; // a big chunk
                            int read;
                            while ((read = fi.read(buffer)) > 0)
                                baos.write(buffer, 0, read);
                            byte[] classBytes= baos.toByteArray();

                            return defineClass(name, classBytes, 0,
                                    classBytes.length);
                        } catch (Exception e) {
                            throw new ClassNotFoundException(name);
                        }
                    }
                }, acc);
    } catch (java.security.PrivilegedActionException pae) {
        return super.findClass(name);
    }
}
}
    ClassLoader classLoader = new CustomClassLoader(ClassLoader.getSystemClassLoader());
    Class stringClass = (new CustomClassLoader(ClassLoader.getSystemClassLoader())).findClass(packageName+"."+javaFileName);
    Object  t = (Object) stringClass.newInstance();